commit
127d40e9a6
98 changed files with 4055 additions and 1366 deletions
|
@ -3,16 +3,22 @@
|
||||||
###############
|
###############
|
||||||
|
|
||||||
.git/
|
.git/
|
||||||
plugins/
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
deploy/
|
||||||
|
dist/
|
||||||
|
doc/
|
||||||
|
|
||||||
#########
|
#########
|
||||||
# Files #
|
# Files #
|
||||||
#########
|
#########
|
||||||
|
|
||||||
|
*.so
|
||||||
*.out
|
*.out
|
||||||
main
|
main
|
||||||
inetmock
|
inetmock
|
||||||
README.md
|
README.md
|
||||||
|
LICENSE
|
||||||
.dockerignore
|
.dockerignore
|
||||||
.gitignore
|
.gitignore
|
||||||
Dockerfile
|
Dockerfile
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -16,3 +16,4 @@ main
|
||||||
|
|
||||||
.idea/
|
.idea/
|
||||||
dist/
|
dist/
|
||||||
|
out/
|
|
@ -22,7 +22,7 @@ archives:
|
||||||
wrap_in_directory: true
|
wrap_in_directory: true
|
||||||
files:
|
files:
|
||||||
- config.yaml
|
- config.yaml
|
||||||
- plugins/*.so
|
- "*.so"
|
||||||
checksum:
|
checksum:
|
||||||
name_template: 'checksums.txt'
|
name_template: 'checksums.txt'
|
||||||
snapshot:
|
snapshot:
|
||||||
|
|
|
@ -38,7 +38,7 @@ WORKDIR /app
|
||||||
|
|
||||||
COPY --from=build /etc/passwd /etc/group /etc/
|
COPY --from=build /etc/passwd /etc/group /etc/
|
||||||
COPY --from=build --chown=$USER /work/inetmock ./
|
COPY --from=build --chown=$USER /work/inetmock ./
|
||||||
COPY --from=build --chown=$USER /work/plugins/ ./plugins/
|
COPY --from=build --chown=$USER /work/*.so ./plugins/
|
||||||
|
|
||||||
USER $USER:$USER
|
USER $USER:$USER
|
||||||
|
|
||||||
|
|
32
Makefile
32
Makefile
|
@ -2,33 +2,36 @@ VERSION = $(shell git describe --dirty --tags --always)
|
||||||
DIR = $(dir $(realpath $(firstword $(MAKEFILE_LIST))))
|
DIR = $(dir $(realpath $(firstword $(MAKEFILE_LIST))))
|
||||||
BUILD_PATH = $(DIR)/main.go
|
BUILD_PATH = $(DIR)/main.go
|
||||||
PKGS = $(shell go list ./...)
|
PKGS = $(shell go list ./...)
|
||||||
TEST_PKGS = $(shell find . -type f -name "*_test.go" -not -path "./pkg/plugins/*" -printf '%h\n' | sort -u)
|
TEST_PKGS = $(shell find . -type f -name "*_test.go" -not -path "./plugins/*" -not -path "*/mock/*" -printf '%h\n' | sort -u)
|
||||||
GOARGS = GOOS=linux GOARCH=amd64
|
GOARGS = GOOS=linux GOARCH=amd64
|
||||||
GO_BUILD_ARGS = -ldflags="-w -s"
|
GO_BUILD_ARGS = -ldflags="-w -s"
|
||||||
GO_CONTAINER_BUILD_ARGS = -ldflags="-w -s" -a -installsuffix cgo
|
GO_CONTAINER_BUILD_ARGS = -ldflags="-w -s" -a -installsuffix cgo
|
||||||
GO_DEBUG_BUILD_ARGS = -gcflags "all=-N -l"
|
GO_DEBUG_BUILD_ARGS = -gcflags "all=-N -l"
|
||||||
BINARY_NAME = inetmock
|
BINARY_NAME = inetmock
|
||||||
PLUGINS = $(wildcard $(DIR)pkg/plugins/*/.)
|
PLUGINS = $(wildcard $(DIR)plugins/*/.)
|
||||||
DEBUG_PORT = 2345
|
DEBUG_PORT = 2345
|
||||||
DEBUG_ARGS?= --development-logs=true
|
DEBUG_ARGS?= --development-logs=true
|
||||||
INETMOCK_PLUGINS_DIRECTORY = $(DIR)
|
CONTAINER_BUILDER ?= podman
|
||||||
|
DOCKER_IMAGE ?= inetmock
|
||||||
.PHONY: clean all format deps compile debug snapshot-release test cli-cover-report html-cover-report plugins $(PLUGINS)
|
|
||||||
|
|
||||||
|
.PHONY: clean all format deps update-deps compile debug generate snapshot-release test cli-cover-report html-cover-report plugins $(PLUGINS) $(GO_GEN_FILES)
|
||||||
all: clean format compile test plugins
|
all: clean format compile test plugins
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@find $(DIR) -type f \( -name "*.out" -or -name "*.so" \) -exec rm -f {} \;
|
@find $(DIR) -type f \( -name "*.out" -or -name "*.so" \) -exec rm -f {} \;
|
||||||
@rm -rf $(DIR)plugins
|
@rm -rf $(DIR)*.so
|
||||||
@rm -f $(DIR)$(BINARY_NAME) $(DIR)main
|
@rm -f $(DIR)$(BINARY_NAME) $(DIR)main
|
||||||
|
|
||||||
format:
|
format:
|
||||||
@go fmt $(PKGS)
|
@go fmt $(PKGS)
|
||||||
|
|
||||||
deps:
|
deps:
|
||||||
@go mod tidy
|
|
||||||
@go build -v $(BUILD_PATH)
|
@go build -v $(BUILD_PATH)
|
||||||
|
|
||||||
|
update-deps:
|
||||||
|
@go mod tidy
|
||||||
|
@go get -u
|
||||||
|
|
||||||
compile: deps
|
compile: deps
|
||||||
ifdef DEBUG
|
ifdef DEBUG
|
||||||
@echo 'Compiling for debugging...'
|
@echo 'Compiling for debugging...'
|
||||||
|
@ -41,26 +44,31 @@ else
|
||||||
@$(GOARGS) go build $(GO_BUILD_ARGS) -o $(DIR)$(BINARY_NAME) $(BUILD_PATH)
|
@$(GOARGS) go build $(GO_BUILD_ARGS) -o $(DIR)$(BINARY_NAME) $(BUILD_PATH)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
debug: export INETMOCK_PLUGINS_DIRECTORY = $(DIR)
|
||||||
debug:
|
debug:
|
||||||
@export INETMOCK_PLUGINS_DIRECTORY
|
dlv debug $(DIR) \
|
||||||
@dlv exec $(DIR)$(BINARY_NAME) \
|
|
||||||
--headless \
|
--headless \
|
||||||
--listen=:2345 \
|
--listen=:2345 \
|
||||||
--api-version=2 \
|
--api-version=2 \
|
||||||
--accept-multiclient \
|
|
||||||
-- $(DEBUG_ARGS)
|
-- $(DEBUG_ARGS)
|
||||||
|
|
||||||
|
generate:
|
||||||
|
@go generate ./...
|
||||||
|
|
||||||
snapshot-release:
|
snapshot-release:
|
||||||
@goreleaser release --snapshot --skip-publish --rm-dist
|
@goreleaser release --snapshot --skip-publish --rm-dist
|
||||||
|
|
||||||
|
container:
|
||||||
|
@$(CONTAINER_BUILDER) build -t $(DOCKER_IMAGE):latest -f $(DIR)Dockerfile $(DIR)
|
||||||
|
|
||||||
test:
|
test:
|
||||||
@go test -coverprofile=./cov-raw.out -v $(TEST_PKGS)
|
@go test -coverprofile=./cov-raw.out -v $(TEST_PKGS)
|
||||||
@cat ./cov-raw.out | grep -v "generated" > ./cov.out
|
@cat ./cov-raw.out | grep -v "generated" > ./cov.out
|
||||||
|
|
||||||
cli-cover-report:
|
cli-cover-report: test
|
||||||
@go tool cover -func=cov.out
|
@go tool cover -func=cov.out
|
||||||
|
|
||||||
html-cover-report:
|
html-cover-report: test
|
||||||
@go tool cover -html=cov.out -o .coverage.html
|
@go tool cover -html=cov.out -o .coverage.html
|
||||||
|
|
||||||
plugins: $(PLUGINS)
|
plugins: $(PLUGINS)
|
||||||
|
|
75
config.yaml
75
config.yaml
|
@ -1,75 +0,0 @@
|
||||||
endpoints:
|
|
||||||
plainHttp:
|
|
||||||
handler: http_mock
|
|
||||||
listenAddress: 0.0.0.0
|
|
||||||
port: 80
|
|
||||||
options:
|
|
||||||
rules:
|
|
||||||
- pattern: ".*\\.(?i)exe"
|
|
||||||
response: ./assets/fakeFiles/sample.exe
|
|
||||||
- pattern: ".*\\.(?i)(jpg|jpeg)"
|
|
||||||
response: ./assets/fakeFiles/default.jpg
|
|
||||||
- pattern: ".*\\.(?i)png"
|
|
||||||
response: ./assets/fakeFiles/default.png
|
|
||||||
- pattern: ".*\\.(?i)gif"
|
|
||||||
response: ./assets/fakeFiles/default.gif
|
|
||||||
- pattern: ".*\\.(?i)ico"
|
|
||||||
response: ./assets/fakeFiles/default.ico
|
|
||||||
- pattern: ".*\\.(?i)txt"
|
|
||||||
response: ./assets/fakeFiles/default.txt
|
|
||||||
- pattern: ".*"
|
|
||||||
response: ./assets/fakeFiles/default.html
|
|
||||||
httpsDowngrade:
|
|
||||||
handler: tls_interceptor
|
|
||||||
listenAddress: 0.0.0.0
|
|
||||||
port: 443
|
|
||||||
options:
|
|
||||||
ecdsaCurve: P256
|
|
||||||
validity:
|
|
||||||
ca:
|
|
||||||
notBeforeRelative: 17520h
|
|
||||||
notAfterRelative: 17520h
|
|
||||||
domain:
|
|
||||||
notBeforeRelative: 168h
|
|
||||||
notAfterRelative: 168h
|
|
||||||
rootCaCert:
|
|
||||||
publicKey: ./ca.pem
|
|
||||||
privateKey: ./ca.key
|
|
||||||
certCachePath: /tmp/inetmock/
|
|
||||||
target:
|
|
||||||
ipAddress: 127.0.0.1
|
|
||||||
port: 80
|
|
||||||
plainDns:
|
|
||||||
handler: dns_mock
|
|
||||||
listenAddress: 0.0.0.0
|
|
||||||
port: 53
|
|
||||||
options:
|
|
||||||
rules:
|
|
||||||
- pattern: ".*\\.google\\.com"
|
|
||||||
response: 1.1.1.1
|
|
||||||
- pattern: ".*\\.reddit\\.com"
|
|
||||||
response: 2.2.2.2
|
|
||||||
fallback:
|
|
||||||
strategy: incremental
|
|
||||||
args:
|
|
||||||
startIP: 10.0.0.0
|
|
||||||
dnsOverTlsDowngrade:
|
|
||||||
handler: tls_interceptor
|
|
||||||
listenAddress: 0.0.0.0
|
|
||||||
port: 853
|
|
||||||
options:
|
|
||||||
ecdsaCurve: P256
|
|
||||||
validity:
|
|
||||||
ca:
|
|
||||||
notBeforeRelative: 17520h
|
|
||||||
notAfterRelative: 17520h
|
|
||||||
domain:
|
|
||||||
notBeforeRelative: 168h
|
|
||||||
notAfterRelative: 168h
|
|
||||||
rootCaCert:
|
|
||||||
publicKey: ./ca.pem
|
|
||||||
privateKey: ./ca.key
|
|
||||||
certCachePath: /tmp/inetmock/
|
|
||||||
target:
|
|
||||||
ipAddress: 127.0.0.1
|
|
||||||
port: 53
|
|
1
config.yaml
Symbolic link
1
config.yaml
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
mock_config.yaml
|
2
deploy/inetmock.default
Normal file
2
deploy/inetmock.default
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
INETMOCK_PLUGINS_DIRECTORY=/usr/lib/inetmock/plugins
|
||||||
|
OPTIONS="--config=/etc/inetmock/config.yaml"
|
15
deploy/inetmock.service
Normal file
15
deploy/inetmock.service
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
[Unit]
|
||||||
|
Description=INetMock is a simple service to simulate a valid internet connection
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=inetmock
|
||||||
|
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||||
|
MemoryMax=50M
|
||||||
|
CPUQuota=20%
|
||||||
|
EnvironmentFile=/etc/default/inetmock
|
||||||
|
ExecStart=/usr/bin/inetmock $OPTIONS
|
||||||
|
WorkingDirectory=/var/lib/inetmock
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
18
go.mod
18
go.mod
|
@ -3,11 +3,19 @@ module github.com/baez90/inetmock
|
||||||
go 1.13
|
go 1.13
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/spf13/cobra v0.0.6
|
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||||
|
github.com/golang/mock v1.4.3
|
||||||
|
github.com/mitchellh/mapstructure v1.2.2 // indirect
|
||||||
|
github.com/pelletier/go-toml v1.7.0 // indirect
|
||||||
|
github.com/spf13/afero v1.2.2 // indirect
|
||||||
|
github.com/spf13/cast v1.3.1 // indirect
|
||||||
|
github.com/spf13/cobra v1.0.0
|
||||||
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/spf13/viper v1.4.0
|
github.com/spf13/viper v1.6.3
|
||||||
go.uber.org/zap v1.14.1
|
go.uber.org/zap v1.15.0
|
||||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe // indirect
|
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f // indirect
|
||||||
|
golang.org/x/text v0.3.2 // indirect
|
||||||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425 // indirect
|
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425 // indirect
|
||||||
gopkg.in/yaml.v2 v2.2.8 // indirect
|
gopkg.in/ini.v1 v1.55.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
78
go.sum
78
go.sum
|
@ -11,6 +11,7 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
|
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||||
|
@ -20,8 +21,9 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
|
@ -31,12 +33,18 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a
|
||||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/mock v1.1.1 h1:G5FRp8JnTd7RQH5kemVNlMeyXQAztQ3mOWV95KxsXH8=
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw=
|
||||||
|
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||||
|
@ -46,10 +54,12 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
|
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||||
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
|
||||||
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.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
|
@ -57,16 +67,22 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
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 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
|
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
|
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||||
|
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
|
github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4=
|
||||||
|
github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
|
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/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
|
github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI=
|
||||||
|
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
@ -85,30 +101,38 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
|
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
|
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||||
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
||||||
|
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs=
|
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
||||||
github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
|
||||||
|
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||||
|
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
|
|
||||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||||
|
github.com/spf13/viper v1.6.3 h1:pDDu1OyEDTKzpJwdq4TiuLyMsUgRa/BT5cn5O62NoHs=
|
||||||
|
github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
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/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.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||||
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
|
@ -123,13 +147,11 @@ go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKY
|
||||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
|
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
|
||||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo=
|
go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM=
|
||||||
go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/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-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk=
|
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
|
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
@ -148,27 +170,29 @@ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAG
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
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-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/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-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe h1:6fAMxZRR6sl1Uq8U61gxU+kPTs2tR8uOySCbBP7BN/M=
|
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8=
|
||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
|
|
||||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425 h1:VvQyQJN0tSuecqgcIxMWnnfG5kSmgy9KZR9sW3W5QeA=
|
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425 h1:VvQyQJN0tSuecqgcIxMWnnfG5kSmgy9KZR9sW3W5QeA=
|
||||||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
@ -183,12 +207,18 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
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/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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
|
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ=
|
||||||
|
gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
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.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
|
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||||
|
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||||
|
|
144
internal/cmd/ca.go
Normal file
144
internal/cmd/ca.go
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"github.com/baez90/inetmock/pkg/cert"
|
||||||
|
"github.com/baez90/inetmock/pkg/logging"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
generateCACommonName = "cn"
|
||||||
|
generateCaOrganizationName = "o"
|
||||||
|
generateCaOrganizationalUnitName = "ou"
|
||||||
|
generateCaCountryName = "c"
|
||||||
|
generateCaLocalityName = "l"
|
||||||
|
generateCaStateName = "st"
|
||||||
|
generateCaStreetAddressName = "street-address"
|
||||||
|
generateCaPostalCodeName = "postal-code"
|
||||||
|
generateCACertOutPath = "out-dir"
|
||||||
|
generateCACurveName = "curve"
|
||||||
|
generateCANotBeforeRelative = "not-before"
|
||||||
|
generateCANotAfterRelative = "not-after"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
generateCaCmd *cobra.Command
|
||||||
|
caCertOptions cert.GenerationOptions
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
generateCaCmd = &cobra.Command{
|
||||||
|
Use: "generate-ca",
|
||||||
|
Short: "Generate a new CA certificate and corresponding key",
|
||||||
|
Long: ``,
|
||||||
|
Run: runGenerateCA,
|
||||||
|
}
|
||||||
|
|
||||||
|
generateCaCmd.Flags().StringVar(&caCertOptions.CommonName, generateCACommonName, "INetMock", "Certificate Common Name that will also be used as file name during generation.")
|
||||||
|
generateCaCmd.Flags().StringSliceVar(&caCertOptions.Organization, generateCaOrganizationName, nil, "Organization information to append to certificate")
|
||||||
|
generateCaCmd.Flags().StringSliceVar(&caCertOptions.OrganizationalUnit, generateCaOrganizationalUnitName, nil, "Organizational unit information to append to certificate")
|
||||||
|
generateCaCmd.Flags().StringSliceVar(&caCertOptions.Country, generateCaCountryName, nil, "Country information to append to certificate")
|
||||||
|
generateCaCmd.Flags().StringSliceVar(&caCertOptions.Province, generateCaStateName, nil, "State information to append to certificate")
|
||||||
|
generateCaCmd.Flags().StringSliceVar(&caCertOptions.Locality, generateCaLocalityName, nil, "Locality information to append to certificate")
|
||||||
|
generateCaCmd.Flags().StringSliceVar(&caCertOptions.StreetAddress, generateCaStreetAddressName, nil, "Street address information to append to certificate")
|
||||||
|
generateCaCmd.Flags().StringSliceVar(&caCertOptions.PostalCode, generateCaPostalCodeName, nil, "Postal code information to append to certificate")
|
||||||
|
generateCaCmd.Flags().String(generateCACertOutPath, "", "Path where CA files should be stored")
|
||||||
|
generateCaCmd.Flags().String(generateCACurveName, "", "Name of the curve to use, if empty ED25519 is used, other valid values are [P224, P256,P384,P521]")
|
||||||
|
generateCaCmd.Flags().Duration(generateCANotBeforeRelative, 17520*time.Hour, "Relative time value since when in the past the CA certificate should be valid. The value has a time unit, the greatest time unit is h for hour.")
|
||||||
|
generateCaCmd.Flags().Duration(generateCANotAfterRelative, 17520*time.Hour, "Relative time value until when in the future the CA certificate should be valid. The value has a time unit, the greatest time unit is h for hour.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func runGenerateCA(cmd *cobra.Command, args []string) {
|
||||||
|
var certOutPath, curveName string
|
||||||
|
var notBefore, notAfter time.Duration
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if certOutPath, err = getStringFlag(generateCaCmd, generateCACertOutPath, logger); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if curveName, err = getStringFlag(generateCaCmd, generateCACurveName, logger); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if notBefore, err = getDurationFlag(generateCaCmd, generateCANotBeforeRelative, logger); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if notAfter, err = getDurationFlag(generateCaCmd, generateCANotAfterRelative, logger); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logger, _ := logging.CreateLogger()
|
||||||
|
|
||||||
|
logger = logger.With(
|
||||||
|
zap.String(generateCACurveName, curveName),
|
||||||
|
zap.String(generateCACertOutPath, certOutPath),
|
||||||
|
)
|
||||||
|
|
||||||
|
generator := cert.NewDefaultGenerator(cert.Options{
|
||||||
|
CertCachePath: certOutPath,
|
||||||
|
Curve: cert.CurveType(curveName),
|
||||||
|
Validity: cert.ValidityByPurpose{
|
||||||
|
CA: cert.ValidityDuration{
|
||||||
|
NotAfterRelative: notAfter,
|
||||||
|
NotBeforeRelative: notBefore,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
var caCrt *tls.Certificate
|
||||||
|
if caCrt, err = generator.CACert(caCertOptions); err != nil {
|
||||||
|
logger.Error(
|
||||||
|
"failed to generate CA certificate",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(caCrt.Certificate) < 1 {
|
||||||
|
logger.Error("no public key given for generated CA certificate")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var pubKey *x509.Certificate
|
||||||
|
if pubKey, err = x509.ParseCertificate(caCrt.Certificate[0]); err != nil {
|
||||||
|
logger.Error(
|
||||||
|
"failed to parse public key from generated CA",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pemCrt := cert.NewPEM(caCrt)
|
||||||
|
if err = pemCrt.Write(pubKey.Subject.CommonName, certOutPath); err != nil {
|
||||||
|
logger.Error(
|
||||||
|
"failed to write Ca files",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
logger.Info("completed certificate generation")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDurationFlag(cmd *cobra.Command, flagName string, logger logging.Logger) (val time.Duration, err error) {
|
||||||
|
if val, err = cmd.Flags().GetDuration(flagName); err != nil {
|
||||||
|
logger.Error(
|
||||||
|
"failed to parse parse flag",
|
||||||
|
zap.String("flag", flagName),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getStringFlag(cmd *cobra.Command, flagName string, logger logging.Logger) (val string, err error) {
|
||||||
|
if val, err = cmd.Flags().GetString(flagName); err != nil {
|
||||||
|
logger.Error(
|
||||||
|
"failed to parse parse flag",
|
||||||
|
zap.String("flag", flagName),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
|
@ -1,11 +1,15 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/baez90/inetmock/internal/endpoints"
|
||||||
"github.com/baez90/inetmock/internal/plugins"
|
"github.com/baez90/inetmock/internal/plugins"
|
||||||
|
"github.com/baez90/inetmock/pkg/api"
|
||||||
"github.com/baez90/inetmock/pkg/logging"
|
"github.com/baez90/inetmock/pkg/logging"
|
||||||
"github.com/baez90/inetmock/pkg/path"
|
"github.com/baez90/inetmock/pkg/path"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -24,6 +28,11 @@ func initApp() (err error) {
|
||||||
)
|
)
|
||||||
logger, _ = logging.CreateLogger()
|
logger, _ = logging.CreateLogger()
|
||||||
registry := plugins.Registry()
|
registry := plugins.Registry()
|
||||||
|
endpointManager = endpoints.NewEndpointManager(logger)
|
||||||
|
|
||||||
|
rootCmd.Flags().ParseErrorsWhitelist.UnknownFlags = false
|
||||||
|
_ = rootCmd.ParseFlags(os.Args)
|
||||||
|
|
||||||
if err = appConfig.ReadConfig(configFilePath); err != nil {
|
if err = appConfig.ReadConfig(configFilePath); err != nil {
|
||||||
logger.Error(
|
logger.Error(
|
||||||
"unrecoverable error occurred during reading the config file",
|
"unrecoverable error occurred during reading the config file",
|
||||||
|
@ -34,12 +43,27 @@ func initApp() (err error) {
|
||||||
|
|
||||||
viperInst := viper.GetViper()
|
viperInst := viper.GetViper()
|
||||||
pluginDir := viperInst.GetString("plugins-directory")
|
pluginDir := viperInst.GetString("plugins-directory")
|
||||||
if err = registry.LoadPlugins(pluginDir); err != nil {
|
|
||||||
logger.Error("Failed to load plugins",
|
if err = api.InitServices(viperInst, logger); err != nil {
|
||||||
|
logger.Error(
|
||||||
|
"failed to initialize app services",
|
||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pluginLoadStartTime := time.Now()
|
||||||
|
if err = registry.LoadPlugins(pluginDir); err != nil {
|
||||||
|
logger.Error("Failed to load plugins",
|
||||||
|
zap.String("pluginsDirectory", pluginDir),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pluginLoadDuration := time.Since(pluginLoadStartTime)
|
||||||
|
logger.Info(
|
||||||
|
"loading plugins completed",
|
||||||
|
zap.Duration("pluginLoadDuration", pluginLoadDuration),
|
||||||
|
)
|
||||||
|
|
||||||
pluginsCmd.AddCommand(registry.PluginCommands()...)
|
pluginsCmd.AddCommand(registry.PluginCommands()...)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
|
@ -18,5 +18,5 @@ The easiest way to explore what commands are available is to start with 'inetmoc
|
||||||
This help page contains a list of available sub-commands starting with the name of the plugin as a prefix.
|
This help page contains a list of available sub-commands starting with the name of the plugin as a prefix.
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
rootCmd.AddCommand(pluginsCmd)
|
rootCmd.AddCommand(pluginsCmd, generateCaCmd)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,20 +2,20 @@ package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/baez90/inetmock/internal/config"
|
"github.com/baez90/inetmock/internal/config"
|
||||||
"github.com/baez90/inetmock/internal/plugins"
|
"github.com/baez90/inetmock/internal/endpoints"
|
||||||
"github.com/baez90/inetmock/pkg/api"
|
"github.com/baez90/inetmock/pkg/api"
|
||||||
|
"github.com/baez90/inetmock/pkg/logging"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
logger *zap.Logger
|
logger logging.Logger
|
||||||
rootCmd = cobra.Command{
|
rootCmd = cobra.Command{
|
||||||
Use: "",
|
Use: "",
|
||||||
Short: "INetMock is lightweight internet mock",
|
Short: "INetMock is lightweight internet mock",
|
||||||
|
@ -27,6 +27,7 @@ var (
|
||||||
developmentLogs bool
|
developmentLogs bool
|
||||||
handlers []api.ProtocolHandler
|
handlers []api.ProtocolHandler
|
||||||
appConfig = config.CreateConfig()
|
appConfig = config.CreateConfig()
|
||||||
|
endpointManager endpoints.EndpointManager
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -39,28 +40,21 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func startInetMock(cmd *cobra.Command, args []string) {
|
func startInetMock(cmd *cobra.Command, args []string) {
|
||||||
registry := plugins.Registry()
|
for endpointName := range viper.GetStringMap(config.EndpointsKey) {
|
||||||
var wg sync.WaitGroup
|
handlerSubConfig := viper.Sub(strings.Join([]string{config.EndpointsKey, endpointName}, "."))
|
||||||
|
handlerConfig := config.CreateMultiHandlerConfig(handlerSubConfig)
|
||||||
//todo introduce endpoint type and move startup and shutdown to this type
|
if err := endpointManager.CreateEndpoint(endpointName, handlerConfig); err != nil {
|
||||||
|
|
||||||
for key, val := range viper.GetStringMap(config.EndpointsKey) {
|
|
||||||
handlerSubConfig := viper.Sub(strings.Join([]string{config.EndpointsKey, key, config.OptionsKey}, "."))
|
|
||||||
pluginConfig := config.CreateHandlerConfig(val, handlerSubConfig)
|
|
||||||
logger.Info(key, zap.Any("value", pluginConfig))
|
|
||||||
|
|
||||||
if handler, ok := registry.HandlerForName(pluginConfig.HandlerName()); ok {
|
|
||||||
handlers = append(handlers, handler)
|
|
||||||
go startEndpoint(handler, pluginConfig, logger)
|
|
||||||
wg.Add(1)
|
|
||||||
} else {
|
|
||||||
logger.Warn(
|
logger.Warn(
|
||||||
"no matching handler registered",
|
"error occurred while creating endpoint",
|
||||||
zap.String("handler", pluginConfig.HandlerName()),
|
zap.String("endpointName", endpointName),
|
||||||
|
zap.String("handlerName", handlerConfig.HandlerName()),
|
||||||
|
zap.Error(err),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
endpointManager.StartEndpoints()
|
||||||
|
|
||||||
signalChannel := make(chan os.Signal, 1)
|
signalChannel := make(chan os.Signal, 1)
|
||||||
signal.Notify(signalChannel, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
|
signal.Notify(signalChannel, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
|
||||||
|
|
||||||
|
@ -72,35 +66,7 @@ func startInetMock(cmd *cobra.Command, args []string) {
|
||||||
zap.String("signal", s.String()),
|
zap.String("signal", s.String()),
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, handler := range handlers {
|
endpointManager.ShutdownEndpoints()
|
||||||
go shutdownEndpoint(handler, &wg, logger)
|
|
||||||
}
|
|
||||||
|
|
||||||
wg.Wait()
|
|
||||||
}
|
|
||||||
|
|
||||||
func startEndpoint(handler api.ProtocolHandler, config config.HandlerConfig, logger *zap.Logger) {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
logger.Fatal(
|
|
||||||
"recovered panic during startup of endpoint",
|
|
||||||
zap.Any("recovered", r),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
handler.Run(config)
|
|
||||||
}
|
|
||||||
|
|
||||||
func shutdownEndpoint(handler api.ProtocolHandler, wg *sync.WaitGroup, logger *zap.Logger) {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
logger.Fatal(
|
|
||||||
"recovered panic during shutdown of endpoint",
|
|
||||||
zap.Any("recovered", r),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
handler.Shutdown(wg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExecuteRootCommand() error {
|
func ExecuteRootCommand() error {
|
||||||
|
|
|
@ -22,7 +22,7 @@ type Config interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type config struct {
|
type config struct {
|
||||||
logger *zap.Logger
|
logger logging.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c config) InitConfig(flags *pflag.FlagSet) {
|
func (c config) InitConfig(flags *pflag.FlagSet) {
|
||||||
|
@ -39,6 +39,10 @@ func (c config) InitConfig(flags *pflag.FlagSet) {
|
||||||
|
|
||||||
func (c *config) ReadConfig(configFilePath string) (err error) {
|
func (c *config) ReadConfig(configFilePath string) (err error) {
|
||||||
if configFilePath != "" && path.FileExists(configFilePath) {
|
if configFilePath != "" && path.FileExists(configFilePath) {
|
||||||
|
c.logger.Info(
|
||||||
|
"loading config from passed config file path",
|
||||||
|
zap.String("configFilePath", configFilePath),
|
||||||
|
)
|
||||||
viper.SetConfigFile(configFilePath)
|
viper.SetConfigFile(configFilePath)
|
||||||
}
|
}
|
||||||
if err = viper.ReadInConfig(); err != nil {
|
if err = viper.ReadInConfig(); err != nil {
|
||||||
|
|
49
internal/config/multi_handler_config.go
Normal file
49
internal/config/multi_handler_config.go
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/baez90/inetmock/pkg/api"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MultiHandlerConfig interface {
|
||||||
|
HandlerName() string
|
||||||
|
ListenAddress() string
|
||||||
|
Ports() []uint16
|
||||||
|
Options() *viper.Viper
|
||||||
|
HandlerConfigs() []api.HandlerConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
type multiHandlerConfig struct {
|
||||||
|
handlerName string
|
||||||
|
ports []uint16
|
||||||
|
listenAddress string
|
||||||
|
options *viper.Viper
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMultiHandlerConfig(handlerName string, ports []uint16, listenAddress string, options *viper.Viper) MultiHandlerConfig {
|
||||||
|
return &multiHandlerConfig{handlerName: handlerName, ports: ports, listenAddress: listenAddress, options: options}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m multiHandlerConfig) HandlerName() string {
|
||||||
|
return m.handlerName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m multiHandlerConfig) ListenAddress() string {
|
||||||
|
return m.listenAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m multiHandlerConfig) Ports() []uint16 {
|
||||||
|
return m.ports
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m multiHandlerConfig) Options() *viper.Viper {
|
||||||
|
return m.options
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m multiHandlerConfig) HandlerConfigs() []api.HandlerConfig {
|
||||||
|
configs := make([]api.HandlerConfig, 0)
|
||||||
|
for _, port := range m.ports {
|
||||||
|
configs = append(configs, api.NewHandlerConfig(m.handlerName, port, m.listenAddress, m.options))
|
||||||
|
}
|
||||||
|
return configs
|
||||||
|
}
|
226
internal/config/multi_handler_config_test.go
Normal file
226
internal/config/multi_handler_config_test.go
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/baez90/inetmock/pkg/api"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_multiHandlerConfig_HandlerConfigs(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
handlerName string
|
||||||
|
ports []uint16
|
||||||
|
listenAddress string
|
||||||
|
options *viper.Viper
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
want []api.HandlerConfig
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Get empty array if no ports are set",
|
||||||
|
fields: fields{},
|
||||||
|
want: make([]api.HandlerConfig, 0),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get a single handler config if only one port is set",
|
||||||
|
fields: fields{
|
||||||
|
handlerName: "sampleHandler",
|
||||||
|
ports: []uint16{80},
|
||||||
|
listenAddress: "0.0.0.0",
|
||||||
|
options: nil,
|
||||||
|
},
|
||||||
|
want: []api.HandlerConfig{
|
||||||
|
api.NewHandlerConfig("sampleHandler", 80, "0.0.0.0", nil),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get multiple handler configs if only one port is set",
|
||||||
|
fields: fields{
|
||||||
|
handlerName: "sampleHandler",
|
||||||
|
ports: []uint16{80, 8080},
|
||||||
|
listenAddress: "0.0.0.0",
|
||||||
|
options: nil,
|
||||||
|
},
|
||||||
|
want: []api.HandlerConfig{
|
||||||
|
api.NewHandlerConfig("sampleHandler", 80, "0.0.0.0", nil),
|
||||||
|
api.NewHandlerConfig("sampleHandler", 8080, "0.0.0.0", nil),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
m := multiHandlerConfig{
|
||||||
|
handlerName: tt.fields.handlerName,
|
||||||
|
ports: tt.fields.ports,
|
||||||
|
listenAddress: tt.fields.listenAddress,
|
||||||
|
options: tt.fields.options,
|
||||||
|
}
|
||||||
|
if got := m.HandlerConfigs(); !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("HandlerConfigs() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_multiHandlerConfig_HandlerName(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
handlerName string
|
||||||
|
ports []uint16
|
||||||
|
listenAddress string
|
||||||
|
options *viper.Viper
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Get empty handler name for uninitialized struct",
|
||||||
|
fields: fields{},
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get expected handler name for initialized struct",
|
||||||
|
fields: fields{
|
||||||
|
handlerName: "sampleHandler",
|
||||||
|
},
|
||||||
|
want: "sampleHandler",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
m := multiHandlerConfig{
|
||||||
|
handlerName: tt.fields.handlerName,
|
||||||
|
ports: tt.fields.ports,
|
||||||
|
listenAddress: tt.fields.listenAddress,
|
||||||
|
options: tt.fields.options,
|
||||||
|
}
|
||||||
|
if got := m.HandlerName(); got != tt.want {
|
||||||
|
t.Errorf("HandlerName() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_multiHandlerConfig_ListenAddress(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
handlerName string
|
||||||
|
ports []uint16
|
||||||
|
listenAddress string
|
||||||
|
options *viper.Viper
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Get empty ListenAddress for uninitialized struct",
|
||||||
|
fields: fields{},
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get expected ListenAddress for initialized struct",
|
||||||
|
fields: fields{
|
||||||
|
listenAddress: "0.0.0.0",
|
||||||
|
},
|
||||||
|
want: "0.0.0.0",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
m := multiHandlerConfig{
|
||||||
|
handlerName: tt.fields.handlerName,
|
||||||
|
ports: tt.fields.ports,
|
||||||
|
listenAddress: tt.fields.listenAddress,
|
||||||
|
options: tt.fields.options,
|
||||||
|
}
|
||||||
|
if got := m.ListenAddress(); got != tt.want {
|
||||||
|
t.Errorf("ListenAddress() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_multiHandlerConfig_Options(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
handlerName string
|
||||||
|
ports []uint16
|
||||||
|
listenAddress string
|
||||||
|
options *viper.Viper
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
want *viper.Viper
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Get nil Options for uninitialized struct",
|
||||||
|
fields: fields{},
|
||||||
|
want: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get expected Options for initialized struct",
|
||||||
|
fields: fields{
|
||||||
|
options: viper.New(),
|
||||||
|
},
|
||||||
|
want: viper.New(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
m := multiHandlerConfig{
|
||||||
|
handlerName: tt.fields.handlerName,
|
||||||
|
ports: tt.fields.ports,
|
||||||
|
listenAddress: tt.fields.listenAddress,
|
||||||
|
options: tt.fields.options,
|
||||||
|
}
|
||||||
|
if got := m.Options(); !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("Options() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_multiHandlerConfig_Ports(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
handlerName string
|
||||||
|
ports []uint16
|
||||||
|
listenAddress string
|
||||||
|
options *viper.Viper
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
want []uint16
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Get empty Ports for uninitialized struct",
|
||||||
|
fields: fields{},
|
||||||
|
want: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get expected Ports for initialized struct",
|
||||||
|
fields: fields{
|
||||||
|
ports: []uint16{80, 8080},
|
||||||
|
},
|
||||||
|
want: []uint16{80, 8080},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
m := multiHandlerConfig{
|
||||||
|
handlerName: tt.fields.handlerName,
|
||||||
|
ports: tt.fields.ports,
|
||||||
|
listenAddress: tt.fields.listenAddress,
|
||||||
|
options: tt.fields.options,
|
||||||
|
}
|
||||||
|
if got := m.Ports(); !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("Ports() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
35
internal/config/parsing.go
Normal file
35
internal/config/parsing.go
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
pluginConfigKey = "handler"
|
||||||
|
listenAddressConfigKey = "listenAddress"
|
||||||
|
portConfigKey = "port"
|
||||||
|
portsConfigKey = "ports"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateMultiHandlerConfig(handlerConfig *viper.Viper) MultiHandlerConfig {
|
||||||
|
return NewMultiHandlerConfig(
|
||||||
|
handlerConfig.GetString(pluginConfigKey),
|
||||||
|
portsFromConfig(handlerConfig),
|
||||||
|
handlerConfig.GetString(listenAddressConfigKey),
|
||||||
|
handlerConfig.Sub(OptionsKey),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func portsFromConfig(handlerConfig *viper.Viper) (ports []uint16) {
|
||||||
|
if portsInt := handlerConfig.GetIntSlice(portsConfigKey); len(portsInt) > 0 {
|
||||||
|
for _, port := range portsInt {
|
||||||
|
ports = append(ports, uint16(port))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if portInt := handlerConfig.GetInt(portConfigKey); portInt > 0 {
|
||||||
|
ports = append(ports, uint16(portInt))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
145
internal/config/parsing_test.go
Normal file
145
internal/config/parsing_test.go
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCreateMultiHandlerConfig(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
handlerConfig *viper.Viper
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want MultiHandlerConfig
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Get simple multiHandlerConfig from config",
|
||||||
|
args: args{
|
||||||
|
handlerConfig: configFromString(`
|
||||||
|
handler: sampleHandler
|
||||||
|
listenAddress: 0.0.0.0
|
||||||
|
ports:
|
||||||
|
- 80
|
||||||
|
- 8080
|
||||||
|
options: {}
|
||||||
|
`),
|
||||||
|
},
|
||||||
|
want: &multiHandlerConfig{
|
||||||
|
handlerName: "sampleHandler",
|
||||||
|
ports: []uint16{80, 8080},
|
||||||
|
listenAddress: "0.0.0.0",
|
||||||
|
options: viper.New(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get more complex multiHandlerConfig from config",
|
||||||
|
args: args{
|
||||||
|
handlerConfig: configFromString(`
|
||||||
|
handler: sampleHandler
|
||||||
|
listenAddress: 0.0.0.0
|
||||||
|
ports:
|
||||||
|
- 80
|
||||||
|
- 8080
|
||||||
|
options:
|
||||||
|
optionA: asdf
|
||||||
|
optionB: as1234
|
||||||
|
`),
|
||||||
|
},
|
||||||
|
want: &multiHandlerConfig{
|
||||||
|
handlerName: "sampleHandler",
|
||||||
|
ports: []uint16{80, 8080},
|
||||||
|
listenAddress: "0.0.0.0",
|
||||||
|
options: configFromString(`
|
||||||
|
nesting:
|
||||||
|
optionA: asdf
|
||||||
|
optionB: as1234
|
||||||
|
`).Sub("nesting"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := CreateMultiHandlerConfig(tt.args.handlerConfig); !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("CreateMultiHandlerConfig() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_portsFromConfig(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
handlerConfig *viper.Viper
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantPorts []uint16
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Empty array if config value is not set",
|
||||||
|
args: args{
|
||||||
|
handlerConfig: viper.New(),
|
||||||
|
},
|
||||||
|
wantPorts: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Array of one if `port` is set",
|
||||||
|
args: args{
|
||||||
|
handlerConfig: configFromString(`
|
||||||
|
port: 80
|
||||||
|
`),
|
||||||
|
},
|
||||||
|
wantPorts: []uint16{80},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Array of one if `ports` is set as array",
|
||||||
|
args: args{
|
||||||
|
handlerConfig: configFromString(`
|
||||||
|
ports:
|
||||||
|
- 80
|
||||||
|
`),
|
||||||
|
},
|
||||||
|
wantPorts: []uint16{80},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Array of two if `ports` is set as array",
|
||||||
|
args: args{
|
||||||
|
handlerConfig: configFromString(`
|
||||||
|
ports:
|
||||||
|
- 80
|
||||||
|
- 8080
|
||||||
|
`),
|
||||||
|
},
|
||||||
|
wantPorts: []uint16{80, 8080},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Array of two if `port` is set as array",
|
||||||
|
args: args{
|
||||||
|
handlerConfig: configFromString(`
|
||||||
|
ports:
|
||||||
|
- 80
|
||||||
|
- 8080
|
||||||
|
`),
|
||||||
|
},
|
||||||
|
wantPorts: []uint16{80, 8080},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if gotPorts := portsFromConfig(tt.args.handlerConfig); !reflect.DeepEqual(gotPorts, tt.wantPorts) {
|
||||||
|
t.Errorf("portsFromConfig() = %v, want %v", gotPorts, tt.wantPorts)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func configFromString(yaml string) (config *viper.Viper) {
|
||||||
|
config = viper.New()
|
||||||
|
config.SetConfigType("yaml")
|
||||||
|
_ = config.ReadConfig(bytes.NewBufferString(yaml))
|
||||||
|
return
|
||||||
|
}
|
30
internal/endpoints/endpoint.go
Normal file
30
internal/endpoints/endpoint.go
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
//go:generate mockgen -source=endpoint.go -destination=./../../internal/mock/endpoints/endpoint_mock.go -package=endpoints_mock
|
||||||
|
package endpoints
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/baez90/inetmock/pkg/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Endpoint interface {
|
||||||
|
Start() error
|
||||||
|
Shutdown() error
|
||||||
|
Name() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type endpoint struct {
|
||||||
|
name string
|
||||||
|
handler api.ProtocolHandler
|
||||||
|
config api.HandlerConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e endpoint) Name() string {
|
||||||
|
return e.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *endpoint) Start() (err error) {
|
||||||
|
return e.handler.Start(e.config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *endpoint) Shutdown() (err error) {
|
||||||
|
return e.handler.Shutdown()
|
||||||
|
}
|
131
internal/endpoints/endpoint_manager.go
Normal file
131
internal/endpoints/endpoint_manager.go
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
package endpoints
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/baez90/inetmock/internal/config"
|
||||||
|
"github.com/baez90/inetmock/internal/plugins"
|
||||||
|
"github.com/baez90/inetmock/pkg/logging"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EndpointManager interface {
|
||||||
|
RegisteredEndpoints() []Endpoint
|
||||||
|
StartedEndpoints() []Endpoint
|
||||||
|
CreateEndpoint(name string, multiHandlerConfig config.MultiHandlerConfig) error
|
||||||
|
StartEndpoints()
|
||||||
|
ShutdownEndpoints()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEndpointManager(logger logging.Logger) EndpointManager {
|
||||||
|
return &endpointManager{
|
||||||
|
logger: logger,
|
||||||
|
registry: plugins.Registry(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type endpointManager struct {
|
||||||
|
logger logging.Logger
|
||||||
|
registeredEndpoints []Endpoint
|
||||||
|
properlyStartedEndpoints []Endpoint
|
||||||
|
registry plugins.HandlerRegistry
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e endpointManager) RegisteredEndpoints() []Endpoint {
|
||||||
|
return e.registeredEndpoints
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e endpointManager) StartedEndpoints() []Endpoint {
|
||||||
|
return e.properlyStartedEndpoints
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *endpointManager) CreateEndpoint(name string, multiHandlerConfig config.MultiHandlerConfig) error {
|
||||||
|
for _, handlerConfig := range multiHandlerConfig.HandlerConfigs() {
|
||||||
|
if handler, ok := e.registry.HandlerForName(multiHandlerConfig.HandlerName()); ok {
|
||||||
|
e.registeredEndpoints = append(e.registeredEndpoints, &endpoint{
|
||||||
|
name: name,
|
||||||
|
handler: handler,
|
||||||
|
config: handlerConfig,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("no matching handler registered for names %s", multiHandlerConfig.HandlerName())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *endpointManager) StartEndpoints() {
|
||||||
|
startTime := time.Now()
|
||||||
|
for _, endpoint := range e.registeredEndpoints {
|
||||||
|
endpointLogger := e.logger.With(
|
||||||
|
zap.String("endpoint", endpoint.Name()),
|
||||||
|
)
|
||||||
|
endpointLogger.Info("Starting endpoint")
|
||||||
|
if ok := startEndpoint(endpoint, endpointLogger); ok {
|
||||||
|
e.properlyStartedEndpoints = append(e.properlyStartedEndpoints, endpoint)
|
||||||
|
endpointLogger.Info("successfully started endpoint")
|
||||||
|
} else {
|
||||||
|
endpointLogger.Error("error occurred during endpoint startup - will be skipped for now")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endpointStartupDuration := time.Since(startTime)
|
||||||
|
e.logger.Info(
|
||||||
|
"Startup of all endpoints completed",
|
||||||
|
zap.Duration("startupTime", endpointStartupDuration),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *endpointManager) ShutdownEndpoints() {
|
||||||
|
var waitGroup sync.WaitGroup
|
||||||
|
waitGroup.Add(len(e.properlyStartedEndpoints))
|
||||||
|
|
||||||
|
for _, endpoint := range e.properlyStartedEndpoints {
|
||||||
|
endpointLogger := e.logger.With(
|
||||||
|
zap.String("endpoint", endpoint.Name()),
|
||||||
|
)
|
||||||
|
endpointLogger.Info("Triggering shutdown of endpoint")
|
||||||
|
go shutdownEndpoint(endpoint, endpointLogger, &waitGroup)
|
||||||
|
}
|
||||||
|
|
||||||
|
waitGroup.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func startEndpoint(ep Endpoint, logger logging.Logger) (success bool) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
logger.Fatal(
|
||||||
|
"recovered panic during startup of endpoint",
|
||||||
|
zap.Any("recovered", r),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if err := ep.Start(); err != nil {
|
||||||
|
logger.Error(
|
||||||
|
"failed to start endpoint",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
success = true
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func shutdownEndpoint(ep Endpoint, logger logging.Logger, wg *sync.WaitGroup) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
logger.Fatal(
|
||||||
|
"recovered panic during shutdown of endpoint",
|
||||||
|
zap.Any("recovered", r),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
if err := ep.Shutdown(); err != nil {
|
||||||
|
logger.Error(
|
||||||
|
"Failed to shutdown endpoint",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
118
internal/endpoints/endpoint_manager_test.go
Normal file
118
internal/endpoints/endpoint_manager_test.go
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
package endpoints
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/baez90/inetmock/internal/config"
|
||||||
|
api_mock "github.com/baez90/inetmock/internal/mock/api"
|
||||||
|
logging_mock "github.com/baez90/inetmock/internal/mock/logging"
|
||||||
|
plugins_mock "github.com/baez90/inetmock/internal/mock/plugins"
|
||||||
|
"github.com/baez90/inetmock/internal/plugins"
|
||||||
|
"github.com/baez90/inetmock/pkg/logging"
|
||||||
|
"github.com/golang/mock/gomock"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_endpointManager_CreateEndpoint(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
logger logging.Logger
|
||||||
|
registeredEndpoints []Endpoint
|
||||||
|
properlyStartedEndpoints []Endpoint
|
||||||
|
registry plugins.HandlerRegistry
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
name string
|
||||||
|
multiHandlerConfig config.MultiHandlerConfig
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
wantErr bool
|
||||||
|
wantEndpoints int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Test add endpoint",
|
||||||
|
wantErr: false,
|
||||||
|
wantEndpoints: 1,
|
||||||
|
fields: fields{
|
||||||
|
logger: func() logging.Logger {
|
||||||
|
return logging_mock.NewMockLogger(gomock.NewController(t))
|
||||||
|
}(),
|
||||||
|
registeredEndpoints: nil,
|
||||||
|
properlyStartedEndpoints: nil,
|
||||||
|
registry: func() plugins.HandlerRegistry {
|
||||||
|
registry := plugins_mock.NewMockHandlerRegistry(gomock.NewController(t))
|
||||||
|
registry.
|
||||||
|
EXPECT().
|
||||||
|
HandlerForName("sampleHandler").
|
||||||
|
MinTimes(1).
|
||||||
|
MaxTimes(1).
|
||||||
|
Return(api_mock.NewMockProtocolHandler(gomock.NewController(t)), true)
|
||||||
|
return registry
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
name: "sampleEndpoint",
|
||||||
|
multiHandlerConfig: config.NewMultiHandlerConfig(
|
||||||
|
"sampleHandler",
|
||||||
|
[]uint16{80},
|
||||||
|
"0.0.0.0",
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test add unknown handler",
|
||||||
|
wantErr: true,
|
||||||
|
wantEndpoints: 0,
|
||||||
|
fields: fields{
|
||||||
|
logger: func() logging.Logger {
|
||||||
|
return logging_mock.NewMockLogger(gomock.NewController(t))
|
||||||
|
}(),
|
||||||
|
registeredEndpoints: nil,
|
||||||
|
properlyStartedEndpoints: nil,
|
||||||
|
registry: func() plugins.HandlerRegistry {
|
||||||
|
registry := plugins_mock.NewMockHandlerRegistry(gomock.NewController(t))
|
||||||
|
registry.
|
||||||
|
EXPECT().
|
||||||
|
HandlerForName("sampleHandler").
|
||||||
|
MinTimes(1).
|
||||||
|
MaxTimes(1).
|
||||||
|
Return(nil, false)
|
||||||
|
return registry
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
name: "sampleEndpoint",
|
||||||
|
multiHandlerConfig: config.NewMultiHandlerConfig(
|
||||||
|
"sampleHandler",
|
||||||
|
[]uint16{80},
|
||||||
|
"0.0.0.0",
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
e := &endpointManager{
|
||||||
|
logger: tt.fields.logger,
|
||||||
|
registeredEndpoints: tt.fields.registeredEndpoints,
|
||||||
|
properlyStartedEndpoints: tt.fields.properlyStartedEndpoints,
|
||||||
|
registry: tt.fields.registry,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := e.CreateEndpoint(tt.args.name, tt.args.multiHandlerConfig); (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("CreateEndpoint() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(e.RegisteredEndpoints()) != tt.wantEndpoints {
|
||||||
|
t.Errorf("RegisteredEndpoints() = %d, want = 1", len(e.RegisteredEndpoints()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(e.RegisteredEndpoints()) > 0 && e.RegisteredEndpoints()[0].Name() != tt.args.name {
|
||||||
|
t.Errorf("Name() = %s, want = %s", e.RegisteredEndpoints()[0].Name(), tt.args.name)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
178
internal/endpoints/endpoint_test.go
Normal file
178
internal/endpoints/endpoint_test.go
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
package endpoints
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
api_mock "github.com/baez90/inetmock/internal/mock/api"
|
||||||
|
"github.com/baez90/inetmock/pkg/api"
|
||||||
|
"github.com/golang/mock/gomock"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_endpoint_Name(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
name string
|
||||||
|
handler api.ProtocolHandler
|
||||||
|
config api.HandlerConfig
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Empty Name if struct is uninitialized",
|
||||||
|
fields: fields{},
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Expected Name if struct is initialized",
|
||||||
|
fields: fields{
|
||||||
|
name: "sampleHandler",
|
||||||
|
},
|
||||||
|
want: "sampleHandler",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
e := endpoint{
|
||||||
|
name: tt.fields.name,
|
||||||
|
handler: tt.fields.handler,
|
||||||
|
config: tt.fields.config,
|
||||||
|
}
|
||||||
|
if got := e.Name(); got != tt.want {
|
||||||
|
t.Errorf("Name() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_endpoint_Shutdown(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
name string
|
||||||
|
handler api.ProtocolHandler
|
||||||
|
config api.HandlerConfig
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Expect no error if mocked handler does not return one",
|
||||||
|
fields: fields{
|
||||||
|
handler: func() api.ProtocolHandler {
|
||||||
|
handler := api_mock.NewMockProtocolHandler(gomock.NewController(t))
|
||||||
|
handler.EXPECT().
|
||||||
|
Shutdown().
|
||||||
|
MaxTimes(1).
|
||||||
|
Return(nil)
|
||||||
|
return handler
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Expect error if mocked handler returns one",
|
||||||
|
fields: fields{
|
||||||
|
handler: func() api.ProtocolHandler {
|
||||||
|
handler := api_mock.NewMockProtocolHandler(gomock.NewController(t))
|
||||||
|
handler.EXPECT().
|
||||||
|
Shutdown().
|
||||||
|
MaxTimes(1).
|
||||||
|
Return(fmt.Errorf(""))
|
||||||
|
return handler
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
e := &endpoint{
|
||||||
|
name: tt.fields.name,
|
||||||
|
handler: tt.fields.handler,
|
||||||
|
config: tt.fields.config,
|
||||||
|
}
|
||||||
|
if err := e.Shutdown(); (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("Shutdown() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_endpoint_Start(t *testing.T) {
|
||||||
|
|
||||||
|
demoHandlerConfig := api.NewHandlerConfig(
|
||||||
|
"sampleHandler",
|
||||||
|
80,
|
||||||
|
"0.0.0.0",
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
|
type fields struct {
|
||||||
|
name string
|
||||||
|
handler api.ProtocolHandler
|
||||||
|
config api.HandlerConfig
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Expect no error if mocked handler does not return one",
|
||||||
|
fields: fields{
|
||||||
|
handler: func() api.ProtocolHandler {
|
||||||
|
handler := api_mock.NewMockProtocolHandler(gomock.NewController(t))
|
||||||
|
handler.EXPECT().
|
||||||
|
Start(nil).
|
||||||
|
MaxTimes(1).
|
||||||
|
Return(nil)
|
||||||
|
return handler
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Expect error if mocked handler returns one",
|
||||||
|
fields: fields{
|
||||||
|
handler: func() api.ProtocolHandler {
|
||||||
|
handler := api_mock.NewMockProtocolHandler(gomock.NewController(t))
|
||||||
|
handler.EXPECT().
|
||||||
|
Start(nil).
|
||||||
|
MaxTimes(1).
|
||||||
|
Return(fmt.Errorf(""))
|
||||||
|
return handler
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Expect config to be passed to Start call",
|
||||||
|
fields: fields{
|
||||||
|
config: demoHandlerConfig,
|
||||||
|
handler: func() api.ProtocolHandler {
|
||||||
|
handler := api_mock.NewMockProtocolHandler(gomock.NewController(t))
|
||||||
|
handler.EXPECT().
|
||||||
|
Start(demoHandlerConfig).
|
||||||
|
MaxTimes(1).
|
||||||
|
Return(fmt.Errorf(""))
|
||||||
|
return handler
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
e := &endpoint{
|
||||||
|
name: tt.fields.name,
|
||||||
|
handler: tt.fields.handler,
|
||||||
|
config: tt.fields.config,
|
||||||
|
}
|
||||||
|
if err := e.Start(); (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("Start() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
//go:generate mockgen -source=loading.go -destination=./../../internal/mock/plugins/handler_registry_mock.go -package=plugins_mock
|
||||||
package plugins
|
package plugins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -42,7 +43,7 @@ func (h *handlerRegistry) HandlerForName(handlerName string) (instance api.Proto
|
||||||
|
|
||||||
func (h *handlerRegistry) RegisterHandler(handlerName string, handlerProvider api.PluginInstanceFactory, subCommands ...*cobra.Command) {
|
func (h *handlerRegistry) RegisterHandler(handlerName string, handlerProvider api.PluginInstanceFactory, subCommands ...*cobra.Command) {
|
||||||
if _, exists := h.handlers[handlerName]; exists {
|
if _, exists := h.handlers[handlerName]; exists {
|
||||||
panic(fmt.Sprintf("plugin %s already registered - there's something strange...in the neighborhood"))
|
panic(fmt.Sprintf("handler with name %s is already registered - there's something strange...in the neighborhood", handlerName))
|
||||||
}
|
}
|
||||||
h.handlers[handlerName] = handlerProvider
|
h.handlers[handlerName] = handlerProvider
|
||||||
|
|
||||||
|
@ -56,7 +57,6 @@ func (h *handlerRegistry) RegisterHandler(handlerName string, handlerProvider ap
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handlerRegistry) LoadPlugins(pluginsPath string) (err error) {
|
func (h *handlerRegistry) LoadPlugins(pluginsPath string) (err error) {
|
||||||
|
|
||||||
if !path.DirExists(pluginsPath) {
|
if !path.DirExists(pluginsPath) {
|
||||||
err = fmt.Errorf("plugins path %s does not exist or is not accessible", pluginsPath)
|
err = fmt.Errorf("plugins path %s does not exist or is not accessible", pluginsPath)
|
||||||
return
|
return
|
||||||
|
|
109
internal/plugins/loading_test.go
Normal file
109
internal/plugins/loading_test.go
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
package plugins
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/baez90/inetmock/pkg/api"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_handlerRegistry_PluginCommands(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
handlers map[string]api.PluginInstanceFactory
|
||||||
|
pluginCommands []*cobra.Command
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
want []*cobra.Command
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Default is an nil array of commands",
|
||||||
|
fields: fields{},
|
||||||
|
want: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Returns a copy of the given array of commands",
|
||||||
|
fields: fields{
|
||||||
|
pluginCommands: []*cobra.Command{
|
||||||
|
{
|
||||||
|
Use: "my-super-command",
|
||||||
|
Short: "bla bla bla, description",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: []*cobra.Command{
|
||||||
|
{
|
||||||
|
Use: "my-super-command",
|
||||||
|
Short: "bla bla bla, description",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
h := handlerRegistry{
|
||||||
|
handlers: tt.fields.handlers,
|
||||||
|
pluginCommands: tt.fields.pluginCommands,
|
||||||
|
}
|
||||||
|
if got := h.PluginCommands(); !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("PluginCommands() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_handlerRegistry_HandlerForName(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
handlers map[string]api.PluginInstanceFactory
|
||||||
|
pluginCommands []*cobra.Command
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
handlerName string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
wantInstance api.ProtocolHandler
|
||||||
|
wantOk bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "No instance if nothing is registered",
|
||||||
|
fields: fields{},
|
||||||
|
args: args{},
|
||||||
|
wantInstance: nil,
|
||||||
|
wantOk: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Nil instance from pseudo factory",
|
||||||
|
fields: fields{
|
||||||
|
handlers: map[string]api.PluginInstanceFactory{
|
||||||
|
"pseudo": func() api.ProtocolHandler {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
handlerName: "pseudo",
|
||||||
|
},
|
||||||
|
wantInstance: nil,
|
||||||
|
wantOk: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
h := &handlerRegistry{
|
||||||
|
handlers: tt.fields.handlers,
|
||||||
|
pluginCommands: tt.fields.pluginCommands,
|
||||||
|
}
|
||||||
|
gotInstance, gotOk := h.HandlerForName(tt.args.handlerName)
|
||||||
|
if !reflect.DeepEqual(gotInstance, tt.wantInstance) {
|
||||||
|
t.Errorf("HandlerForName() gotInstance = %v, want %v", gotInstance, tt.wantInstance)
|
||||||
|
}
|
||||||
|
if gotOk != tt.wantOk {
|
||||||
|
t.Errorf("HandlerForName() gotOk = %v, want %v", gotOk, tt.wantOk)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
80
mock_config.yaml
Normal file
80
mock_config.yaml
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
x-response-rules: &httpResponseRules
|
||||||
|
rules:
|
||||||
|
- pattern: ".*\\.(?i)exe"
|
||||||
|
response: ./assets/fakeFiles/sample.exe
|
||||||
|
- pattern: ".*\\.(?i)(jpg|jpeg)"
|
||||||
|
response: ./assets/fakeFiles/default.jpg
|
||||||
|
- pattern: ".*\\.(?i)png"
|
||||||
|
response: ./assets/fakeFiles/default.png
|
||||||
|
- pattern: ".*\\.(?i)gif"
|
||||||
|
response: ./assets/fakeFiles/default.gif
|
||||||
|
- pattern: ".*\\.(?i)ico"
|
||||||
|
response: ./assets/fakeFiles/default.ico
|
||||||
|
- pattern: ".*\\.(?i)txt"
|
||||||
|
response: ./assets/fakeFiles/default.txt
|
||||||
|
- pattern: ".*"
|
||||||
|
response: ./assets/fakeFiles/default.html
|
||||||
|
|
||||||
|
tls:
|
||||||
|
ecdsaCurve: P256
|
||||||
|
validity:
|
||||||
|
ca:
|
||||||
|
notBeforeRelative: 17520h
|
||||||
|
notAfterRelative: 17520h
|
||||||
|
server:
|
||||||
|
NotBeforeRelative: 168h
|
||||||
|
NotAfterRelative: 168h
|
||||||
|
rootCaCert:
|
||||||
|
publicKey: ./ca.pem
|
||||||
|
privateKey: ./ca.key
|
||||||
|
certCachePath: /tmp/inetmock/
|
||||||
|
|
||||||
|
endpoints:
|
||||||
|
plainHttp:
|
||||||
|
handler: http_mock
|
||||||
|
listenAddress: 0.0.0.0
|
||||||
|
ports:
|
||||||
|
- 80
|
||||||
|
- 8080
|
||||||
|
options:
|
||||||
|
<<: *httpResponseRules
|
||||||
|
proxy:
|
||||||
|
handler: http_proxy
|
||||||
|
listenAddress: 0.0.0.0
|
||||||
|
port: 3128
|
||||||
|
options:
|
||||||
|
target:
|
||||||
|
ipAddress: 127.0.0.1
|
||||||
|
port: 80
|
||||||
|
httpsDowngrade:
|
||||||
|
handler: tls_interceptor
|
||||||
|
listenAddress: 0.0.0.0
|
||||||
|
ports:
|
||||||
|
- 443
|
||||||
|
- 8443
|
||||||
|
options:
|
||||||
|
target:
|
||||||
|
ipAddress: 127.0.0.1
|
||||||
|
port: 80
|
||||||
|
plainDns:
|
||||||
|
handler: dns_mock
|
||||||
|
listenAddress: 0.0.0.0
|
||||||
|
port: 53
|
||||||
|
options:
|
||||||
|
rules:
|
||||||
|
- pattern: ".*\\.google\\.com"
|
||||||
|
response: 1.1.1.1
|
||||||
|
- pattern: ".*\\.reddit\\.com"
|
||||||
|
response: 2.2.2.2
|
||||||
|
fallback:
|
||||||
|
strategy: incremental
|
||||||
|
args:
|
||||||
|
startIP: 10.0.10.0
|
||||||
|
dnsOverTlsDowngrade:
|
||||||
|
handler: tls_interceptor
|
||||||
|
listenAddress: 0.0.0.0
|
||||||
|
port: 853
|
||||||
|
options:
|
||||||
|
target:
|
||||||
|
ipAddress: 127.0.0.1
|
||||||
|
port: 53
|
|
@ -1,22 +1,32 @@
|
||||||
package config
|
package api
|
||||||
|
|
||||||
import "github.com/spf13/viper"
|
import "github.com/spf13/viper"
|
||||||
|
|
||||||
const (
|
type HandlerConfig interface {
|
||||||
pluginConfigKey = "handler"
|
HandlerName() string
|
||||||
listenAddressConfigKey = "listenaddress"
|
ListenAddress() string
|
||||||
portConfigKey = "port"
|
Port() uint16
|
||||||
)
|
Options() *viper.Viper
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHandlerConfig(handlerName string, port uint16, listenAddress string, options *viper.Viper) HandlerConfig {
|
||||||
|
return &handlerConfig{
|
||||||
|
handlerName: handlerName,
|
||||||
|
port: port,
|
||||||
|
listenAddress: listenAddress,
|
||||||
|
options: options,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type handlerConfig struct {
|
type handlerConfig struct {
|
||||||
pluginName string
|
handlerName string
|
||||||
port uint16
|
port uint16
|
||||||
listenAddress string
|
listenAddress string
|
||||||
options *viper.Viper
|
options *viper.Viper
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h handlerConfig) HandlerName() string {
|
func (h handlerConfig) HandlerName() string {
|
||||||
return h.pluginName
|
return h.handlerName
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h handlerConfig) ListenAddress() string {
|
func (h handlerConfig) ListenAddress() string {
|
||||||
|
@ -30,20 +40,3 @@ func (h handlerConfig) Port() uint16 {
|
||||||
func (h handlerConfig) Options() *viper.Viper {
|
func (h handlerConfig) Options() *viper.Viper {
|
||||||
return h.options
|
return h.options
|
||||||
}
|
}
|
||||||
|
|
||||||
type HandlerConfig interface {
|
|
||||||
HandlerName() string
|
|
||||||
ListenAddress() string
|
|
||||||
Port() uint16
|
|
||||||
Options() *viper.Viper
|
|
||||||
}
|
|
||||||
|
|
||||||
func CreateHandlerConfig(configMap interface{}, subConfig *viper.Viper) HandlerConfig {
|
|
||||||
underlyingMap := configMap.(map[string]interface{})
|
|
||||||
return &handlerConfig{
|
|
||||||
pluginName: underlyingMap[pluginConfigKey].(string),
|
|
||||||
listenAddress: underlyingMap[listenAddressConfigKey].(string),
|
|
||||||
port: uint16(underlyingMap[portConfigKey].(int)),
|
|
||||||
options: subConfig,
|
|
||||||
}
|
|
||||||
}
|
|
167
pkg/api/handler_config_test.go
Normal file
167
pkg/api/handler_config_test.go
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_handlerConfig_HandlerName(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
handlerName string
|
||||||
|
port uint16
|
||||||
|
listenAddress string
|
||||||
|
options *viper.Viper
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Get empty HandlerName for uninitialized struct",
|
||||||
|
fields: fields{},
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get expected HandlerName for initialized struct",
|
||||||
|
fields: fields{
|
||||||
|
handlerName: "sampleHandler",
|
||||||
|
},
|
||||||
|
want: "sampleHandler",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
h := handlerConfig{
|
||||||
|
handlerName: tt.fields.handlerName,
|
||||||
|
port: tt.fields.port,
|
||||||
|
listenAddress: tt.fields.listenAddress,
|
||||||
|
options: tt.fields.options,
|
||||||
|
}
|
||||||
|
if got := h.HandlerName(); got != tt.want {
|
||||||
|
t.Errorf("HandlerName() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_handlerConfig_ListenAddress(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
handlerName string
|
||||||
|
port uint16
|
||||||
|
listenAddress string
|
||||||
|
options *viper.Viper
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Get empty ListenAddress for uninitialized struct",
|
||||||
|
fields: fields{},
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get expected ListenAddress for initialized struct",
|
||||||
|
fields: fields{
|
||||||
|
listenAddress: "0.0.0.0",
|
||||||
|
},
|
||||||
|
want: "0.0.0.0",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
h := handlerConfig{
|
||||||
|
handlerName: tt.fields.handlerName,
|
||||||
|
port: tt.fields.port,
|
||||||
|
listenAddress: tt.fields.listenAddress,
|
||||||
|
options: tt.fields.options,
|
||||||
|
}
|
||||||
|
if got := h.ListenAddress(); got != tt.want {
|
||||||
|
t.Errorf("ListenAddress() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_handlerConfig_Options(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
handlerName string
|
||||||
|
port uint16
|
||||||
|
listenAddress string
|
||||||
|
options *viper.Viper
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
want *viper.Viper
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Get nil Options for uninitialized struct",
|
||||||
|
fields: fields{},
|
||||||
|
want: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get expected Options for initialized struct",
|
||||||
|
fields: fields{
|
||||||
|
options: viper.New(),
|
||||||
|
},
|
||||||
|
want: viper.New(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
h := handlerConfig{
|
||||||
|
handlerName: tt.fields.handlerName,
|
||||||
|
port: tt.fields.port,
|
||||||
|
listenAddress: tt.fields.listenAddress,
|
||||||
|
options: tt.fields.options,
|
||||||
|
}
|
||||||
|
if got := h.Options(); !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("Options() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_handlerConfig_Port(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
handlerName string
|
||||||
|
port uint16
|
||||||
|
listenAddress string
|
||||||
|
options *viper.Viper
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
want uint16
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Get empty Port for uninitialized struct",
|
||||||
|
fields: fields{},
|
||||||
|
want: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get expected Port for initialized struct",
|
||||||
|
fields: fields{
|
||||||
|
port: 80,
|
||||||
|
},
|
||||||
|
want: 80,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
h := handlerConfig{
|
||||||
|
handlerName: tt.fields.handlerName,
|
||||||
|
port: tt.fields.port,
|
||||||
|
listenAddress: tt.fields.listenAddress,
|
||||||
|
options: tt.fields.options,
|
||||||
|
}
|
||||||
|
if got := h.Port(); got != tt.want {
|
||||||
|
t.Errorf("Port() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,8 @@
|
||||||
|
//go:generate mockgen -source=protocol_handler.go -destination=./../../internal/mock/api/protocol_handler_mock.go -package=api_mock
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/baez90/inetmock/internal/config"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"sync"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type PluginInstanceFactory func() ProtocolHandler
|
type PluginInstanceFactory func() ProtocolHandler
|
||||||
|
@ -11,6 +10,6 @@ type PluginInstanceFactory func() ProtocolHandler
|
||||||
type LoggingFactory func() (*zap.Logger, error)
|
type LoggingFactory func() (*zap.Logger, error)
|
||||||
|
|
||||||
type ProtocolHandler interface {
|
type ProtocolHandler interface {
|
||||||
Run(config config.HandlerConfig)
|
Start(config HandlerConfig) error
|
||||||
Shutdown(wg *sync.WaitGroup)
|
Shutdown() error
|
||||||
}
|
}
|
||||||
|
|
41
pkg/api/services.go
Normal file
41
pkg/api/services.go
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/baez90/inetmock/pkg/cert"
|
||||||
|
"github.com/baez90/inetmock/pkg/logging"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
svcs Services
|
||||||
|
)
|
||||||
|
|
||||||
|
type Services interface {
|
||||||
|
CertStore() cert.Store
|
||||||
|
}
|
||||||
|
|
||||||
|
type services struct {
|
||||||
|
certStore cert.Store
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitServices(
|
||||||
|
config *viper.Viper,
|
||||||
|
logger logging.Logger,
|
||||||
|
) error {
|
||||||
|
certStore, err := cert.NewDefaultStore(config, logger)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
svcs = &services{
|
||||||
|
certStore: certStore,
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ServicesInstance() Services {
|
||||||
|
return svcs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *services) CertStore() cert.Store {
|
||||||
|
return s.certStore
|
||||||
|
}
|
22
pkg/cert/addr_utils.go
Normal file
22
pkg/cert/addr_utils.go
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package cert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func extractIPFromAddress(addr string) (ip string, err error) {
|
||||||
|
if idx := strings.LastIndex(addr, ":"); idx < 0 {
|
||||||
|
err = fmt.Errorf("addr %s does not match expected scheme <ip>:<port>", addr)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* get IP part of address */
|
||||||
|
ip = addr[0:idx]
|
||||||
|
|
||||||
|
/* trim [ ] for IPv6 addresses */
|
||||||
|
if ip[0] == '[' {
|
||||||
|
ip = ip[1 : len(ip)-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package cert
|
||||||
|
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
78
pkg/cert/cache.go
Normal file
78
pkg/cert/cache.go
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
//go:generate mockgen -source=cache.go -destination=./../../internal/mock/cert/cert_cache_mock.go -package=cert_mock
|
||||||
|
|
||||||
|
package cert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Cache interface {
|
||||||
|
Put(cert *tls.Certificate) error
|
||||||
|
Get(cn string) (*tls.Certificate, bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFileSystemCache(certCachePath string, source TimeSource) Cache {
|
||||||
|
return &fileSystemCache{
|
||||||
|
certCachePath: certCachePath,
|
||||||
|
inMemCache: make(map[string]*tls.Certificate),
|
||||||
|
timeSource: source,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type fileSystemCache struct {
|
||||||
|
certCachePath string
|
||||||
|
inMemCache map[string]*tls.Certificate
|
||||||
|
timeSource TimeSource
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fileSystemCache) Put(cert *tls.Certificate) (err error) {
|
||||||
|
if cert == nil {
|
||||||
|
err = errors.New("cert may not be nil")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var cn string
|
||||||
|
if len(cert.Certificate) > 0 {
|
||||||
|
if pubKey, err := x509.ParseCertificate(cert.Certificate[0]); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
cn = pubKey.Subject.CommonName
|
||||||
|
}
|
||||||
|
|
||||||
|
f.inMemCache[cn] = cert
|
||||||
|
pemCrt := NewPEM(cert)
|
||||||
|
err = pemCrt.Write(cn, f.certCachePath)
|
||||||
|
} else {
|
||||||
|
err = errors.New("no public key present for certificate")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fileSystemCache) Get(cn string) (*tls.Certificate, bool) {
|
||||||
|
|
||||||
|
if crt, ok := f.inMemCache[cn]; ok {
|
||||||
|
return crt, true
|
||||||
|
}
|
||||||
|
|
||||||
|
pemCrt := NewPEM(nil)
|
||||||
|
if err := pemCrt.Read(cn, f.certCachePath); err != nil || pemCrt.Cert() == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
x509Cert, err := x509.ParseCertificate(pemCrt.Cert().Certificate[0])
|
||||||
|
if err == nil && !certShouldBeRenewed(f.timeSource, x509Cert) {
|
||||||
|
return pemCrt.Cert(), true
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func certShouldBeRenewed(timeSource TimeSource, cert *x509.Certificate) bool {
|
||||||
|
lifetime := cert.NotAfter.Sub(cert.NotBefore)
|
||||||
|
// if the cert is closer to the end of the lifetime than lifetime/2 it should be renewed
|
||||||
|
if cert.NotAfter.Sub(timeSource.UTCNow()) < lifetime/4 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
299
pkg/cert/cache_test.go
Normal file
299
pkg/cert/cache_test.go
Normal file
|
@ -0,0 +1,299 @@
|
||||||
|
package cert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"fmt"
|
||||||
|
certmock "github.com/baez90/inetmock/internal/mock/cert"
|
||||||
|
"github.com/golang/mock/gomock"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
cnLocalhost = "localhost"
|
||||||
|
caCN = "UnitTests"
|
||||||
|
serverRelativeValidity = 24 * time.Hour
|
||||||
|
caRelativeValidity = 168 * time.Hour
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
serverCN = fmt.Sprintf("%s-%d", cnLocalhost, time.Now().Unix())
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_certShouldBeRenewed(t *testing.T) {
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
defer ctrl.Finish()
|
||||||
|
type args struct {
|
||||||
|
timeSource TimeSource
|
||||||
|
cert *x509.Certificate
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Expect cert should not be renewed right after creation",
|
||||||
|
args: args{
|
||||||
|
timeSource: func() TimeSource {
|
||||||
|
tsMock := certmock.NewMockTimeSource(ctrl)
|
||||||
|
tsMock.
|
||||||
|
EXPECT().
|
||||||
|
UTCNow().
|
||||||
|
Return(time.Now().UTC()).
|
||||||
|
Times(1)
|
||||||
|
return tsMock
|
||||||
|
}(),
|
||||||
|
cert: &x509.Certificate{
|
||||||
|
NotAfter: time.Now().UTC().Add(serverRelativeValidity),
|
||||||
|
NotBefore: time.Now().UTC().Add(-serverRelativeValidity),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Expect cert should be renewed if the remaining lifetime is less than a quarter of the total lifetime",
|
||||||
|
args: args{
|
||||||
|
timeSource: func() TimeSource {
|
||||||
|
tsMock := certmock.NewMockTimeSource(ctrl)
|
||||||
|
tsMock.
|
||||||
|
EXPECT().
|
||||||
|
UTCNow().
|
||||||
|
Return(time.Now().UTC().Add(serverRelativeValidity/2 + 1*time.Hour)).
|
||||||
|
Times(1)
|
||||||
|
return tsMock
|
||||||
|
}(),
|
||||||
|
cert: &x509.Certificate{
|
||||||
|
NotAfter: time.Now().UTC().Add(serverRelativeValidity),
|
||||||
|
NotBefore: time.Now().UTC().Add(-serverRelativeValidity),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := certShouldBeRenewed(tt.args.timeSource, tt.args.cert); got != tt.want {
|
||||||
|
t.Errorf("certShouldBeRenewed() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_fileSystemCache_Get(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
certCachePath string
|
||||||
|
inMemCache map[string]*tls.Certificate
|
||||||
|
timeSource TimeSource
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
cn string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
wantOk bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Get a miss when no cert is present",
|
||||||
|
fields: fields{
|
||||||
|
certCachePath: os.TempDir(),
|
||||||
|
inMemCache: make(map[string]*tls.Certificate),
|
||||||
|
timeSource: NewTimeSource(),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
cnLocalhost,
|
||||||
|
},
|
||||||
|
wantOk: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get a prepared certificate from the memory cache",
|
||||||
|
fields: func() fields {
|
||||||
|
certGen := setupCertGen()
|
||||||
|
|
||||||
|
caCrt, _ := certGen.CACert(GenerationOptions{
|
||||||
|
CommonName: caCN,
|
||||||
|
})
|
||||||
|
|
||||||
|
srvCrt, _ := certGen.ServerCert(GenerationOptions{
|
||||||
|
CommonName: cnLocalhost,
|
||||||
|
}, caCrt)
|
||||||
|
|
||||||
|
return fields{
|
||||||
|
certCachePath: os.TempDir(),
|
||||||
|
inMemCache: map[string]*tls.Certificate{
|
||||||
|
cnLocalhost: srvCrt,
|
||||||
|
},
|
||||||
|
timeSource: NewTimeSource(),
|
||||||
|
}
|
||||||
|
}(),
|
||||||
|
args: args{
|
||||||
|
cn: cnLocalhost,
|
||||||
|
},
|
||||||
|
wantOk: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get a prepared certificate from the file system",
|
||||||
|
fields: func() fields {
|
||||||
|
certGen := setupCertGen()
|
||||||
|
|
||||||
|
caCrt, _ := certGen.CACert(GenerationOptions{
|
||||||
|
CommonName: "INetMock",
|
||||||
|
})
|
||||||
|
|
||||||
|
srvCrt, _ := certGen.ServerCert(GenerationOptions{
|
||||||
|
CommonName: serverCN,
|
||||||
|
}, caCrt)
|
||||||
|
|
||||||
|
pem := NewPEM(srvCrt)
|
||||||
|
if err := pem.Write(serverCN, os.TempDir()); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Cleanup(func() {
|
||||||
|
for _, f := range []string{
|
||||||
|
path.Join(os.TempDir(), fmt.Sprintf("%s.pem", serverCN)),
|
||||||
|
path.Join(os.TempDir(), fmt.Sprintf("%s.key", serverCN)),
|
||||||
|
} {
|
||||||
|
_ = os.Remove(f)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return fields{
|
||||||
|
certCachePath: os.TempDir(),
|
||||||
|
inMemCache: make(map[string]*tls.Certificate),
|
||||||
|
timeSource: NewTimeSource(),
|
||||||
|
}
|
||||||
|
}(),
|
||||||
|
args: args{
|
||||||
|
cn: serverCN,
|
||||||
|
},
|
||||||
|
wantOk: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
f := &fileSystemCache{
|
||||||
|
certCachePath: tt.fields.certCachePath,
|
||||||
|
inMemCache: tt.fields.inMemCache,
|
||||||
|
timeSource: tt.fields.timeSource,
|
||||||
|
}
|
||||||
|
gotCrt, gotOk := f.Get(tt.args.cn)
|
||||||
|
|
||||||
|
if gotOk && (gotCrt == nil || !reflect.DeepEqual(reflect.TypeOf(new(tls.Certificate)), reflect.TypeOf(gotCrt))) {
|
||||||
|
t.Errorf("Wanted propert certificate but got %v", gotCrt)
|
||||||
|
}
|
||||||
|
|
||||||
|
if gotOk != tt.wantOk {
|
||||||
|
t.Errorf("Get() gotOk = %v, want %v", gotOk, tt.wantOk)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_fileSystemCache_Put(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
certCachePath string
|
||||||
|
inMemCache map[string]*tls.Certificate
|
||||||
|
timeSource TimeSource
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
cert *tls.Certificate
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Want error if nil cert is passed to put",
|
||||||
|
fields: fields{
|
||||||
|
certCachePath: os.TempDir(),
|
||||||
|
inMemCache: make(map[string]*tls.Certificate),
|
||||||
|
timeSource: NewTimeSource(),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
cert: nil,
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Want error if empty cert is passed to put",
|
||||||
|
fields: fields{
|
||||||
|
certCachePath: os.TempDir(),
|
||||||
|
inMemCache: make(map[string]*tls.Certificate),
|
||||||
|
timeSource: NewTimeSource(),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
cert: &tls.Certificate{},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "No error if valid cert is passed",
|
||||||
|
fields: fields{
|
||||||
|
certCachePath: os.TempDir(),
|
||||||
|
inMemCache: make(map[string]*tls.Certificate),
|
||||||
|
timeSource: NewTimeSource(),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
cert: func() *tls.Certificate {
|
||||||
|
gen := setupCertGen()
|
||||||
|
ca, _ := gen.CACert(GenerationOptions{
|
||||||
|
CommonName: caCN,
|
||||||
|
})
|
||||||
|
|
||||||
|
srvCN := fmt.Sprintf("%s-%d", cnLocalhost, time.Now().Unix())
|
||||||
|
|
||||||
|
t.Cleanup(func() {
|
||||||
|
for _, f := range []string{
|
||||||
|
path.Join(os.TempDir(), fmt.Sprintf("%s.pem", srvCN)),
|
||||||
|
path.Join(os.TempDir(), fmt.Sprintf("%s.key", srvCN)),
|
||||||
|
} {
|
||||||
|
_ = os.Remove(f)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
srvCrt, _ := gen.ServerCert(GenerationOptions{
|
||||||
|
CommonName: srvCN,
|
||||||
|
}, ca)
|
||||||
|
return srvCrt
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
f := &fileSystemCache{
|
||||||
|
certCachePath: tt.fields.certCachePath,
|
||||||
|
inMemCache: tt.fields.inMemCache,
|
||||||
|
timeSource: tt.fields.timeSource,
|
||||||
|
}
|
||||||
|
if err := f.Put(tt.args.cert); (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("Put() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupCertGen() Generator {
|
||||||
|
return NewDefaultGenerator(Options{
|
||||||
|
Validity: ValidityByPurpose{
|
||||||
|
Server: ValidityDuration{
|
||||||
|
NotBeforeRelative: serverRelativeValidity,
|
||||||
|
NotAfterRelative: serverRelativeValidity,
|
||||||
|
},
|
||||||
|
CA: ValidityDuration{
|
||||||
|
NotBeforeRelative: caRelativeValidity,
|
||||||
|
NotAfterRelative: caRelativeValidity,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
21
pkg/cert/constants.go
Normal file
21
pkg/cert/constants.go
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package cert
|
||||||
|
|
||||||
|
const (
|
||||||
|
CurveTypeP224 CurveType = "P224"
|
||||||
|
CurveTypeP256 CurveType = "P256"
|
||||||
|
CurveTypeP384 CurveType = "P384"
|
||||||
|
CurveTypeP521 CurveType = "P521"
|
||||||
|
CurveTypeED25519 CurveType = "ED25519"
|
||||||
|
|
||||||
|
defaultServerValidityDuration = "168h"
|
||||||
|
defaultCAValidityDuration = "17520h"
|
||||||
|
|
||||||
|
certCachePathConfigKey = "tls.certCachePath"
|
||||||
|
ecdsaCurveConfigKey = "tls.ecdsaCurve"
|
||||||
|
publicKeyConfigKey = "tls.rootCaCert.publicKey"
|
||||||
|
privateKeyPathConfigKey = "tls.rootCaCert.privateKey"
|
||||||
|
caCertValidityNotBeforeKey = "tls.validity.ca.notBeforeRelative"
|
||||||
|
caCertValidityNotAfterKey = "tls.validity.ca.notAfterRelative"
|
||||||
|
serverCertValidityNotBeforeKey = "tls.validity.server.notBeforeRelative"
|
||||||
|
serverCertValidityNotAfterKey = "tls.validity.server.notAfterRelative"
|
||||||
|
)
|
43
pkg/cert/defaults.go
Normal file
43
pkg/cert/defaults.go
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
package cert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/baez90/inetmock/pkg/defaulting"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
certOptionsDefaulter defaulting.Defaulter = func(instance interface{}) {
|
||||||
|
switch o := instance.(type) {
|
||||||
|
case *GenerationOptions:
|
||||||
|
|
||||||
|
if len(o.Country) < 1 {
|
||||||
|
o.Country = []string{"US"}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(o.Locality) < 1 {
|
||||||
|
o.Locality = []string{"San Francisco"}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(o.Organization) < 1 {
|
||||||
|
o.Organization = []string{"INetMock"}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(o.StreetAddress) < 1 {
|
||||||
|
o.StreetAddress = []string{"Golden Gate Bridge"}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(o.PostalCode) < 1 {
|
||||||
|
o.PostalCode = []string{"94016"}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(o.Province) < 1 {
|
||||||
|
o.Province = []string{""}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
certOptionsType := reflect.TypeOf(GenerationOptions{})
|
||||||
|
defaulters.Register(certOptionsType, certOptionsDefaulter)
|
||||||
|
}
|
39
pkg/cert/defaults_test.go
Normal file
39
pkg/cert/defaults_test.go
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
package cert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_certOptionsDefaulter(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
arg GenerationOptions
|
||||||
|
expected GenerationOptions
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "",
|
||||||
|
arg: GenerationOptions{
|
||||||
|
CommonName: "CA",
|
||||||
|
},
|
||||||
|
expected: GenerationOptions{
|
||||||
|
CommonName: "CA",
|
||||||
|
Country: []string{"US"},
|
||||||
|
Locality: []string{"San Francisco"},
|
||||||
|
Organization: []string{"INetMock"},
|
||||||
|
StreetAddress: []string{"Golden Gate Bridge"},
|
||||||
|
PostalCode: []string{"94016"},
|
||||||
|
Province: []string{""},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
certOptionsDefaulter(&tt.arg)
|
||||||
|
if !reflect.DeepEqual(tt.expected, tt.arg) {
|
||||||
|
t.Errorf("Apply defaulter expected=%v got=%v", tt.expected, tt.arg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
184
pkg/cert/generator.go
Normal file
184
pkg/cert/generator.go
Normal file
|
@ -0,0 +1,184 @@
|
||||||
|
package cert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/ed25519"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"crypto/x509/pkix"
|
||||||
|
"encoding/pem"
|
||||||
|
"github.com/baez90/inetmock/pkg/defaulting"
|
||||||
|
"math/big"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
defaulters = defaulting.New()
|
||||||
|
)
|
||||||
|
|
||||||
|
type GenerationOptions struct {
|
||||||
|
CommonName string
|
||||||
|
Organization []string
|
||||||
|
OrganizationalUnit []string
|
||||||
|
IPAddresses []net.IP
|
||||||
|
DNSNames []string
|
||||||
|
Country []string
|
||||||
|
Province []string
|
||||||
|
Locality []string
|
||||||
|
StreetAddress []string
|
||||||
|
PostalCode []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Generator interface {
|
||||||
|
CACert(options GenerationOptions) (*tls.Certificate, error)
|
||||||
|
ServerCert(options GenerationOptions, ca *tls.Certificate) (*tls.Certificate, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDefaultGenerator(options Options) Generator {
|
||||||
|
return NewGenerator(options, NewTimeSource(), defaultKeyProvider(options))
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGenerator(options Options, source TimeSource, provider KeyProvider) Generator {
|
||||||
|
return &generator{
|
||||||
|
options: options,
|
||||||
|
provider: provider,
|
||||||
|
timeSource: source,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type generator struct {
|
||||||
|
options Options
|
||||||
|
provider KeyProvider
|
||||||
|
timeSource TimeSource
|
||||||
|
outDir string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *generator) privateKey() (key interface{}, err error) {
|
||||||
|
if g.provider != nil {
|
||||||
|
return g.provider()
|
||||||
|
} else {
|
||||||
|
return defaultKeyProvider(g.options)()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *generator) ServerCert(options GenerationOptions, ca *tls.Certificate) (cert *tls.Certificate, err error) {
|
||||||
|
defaulters.Apply(&options)
|
||||||
|
var serialNumber *big.Int
|
||||||
|
if serialNumber, err = generateSerialNumber(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var privateKey interface{}
|
||||||
|
if privateKey, err = g.privateKey(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
template := x509.Certificate{
|
||||||
|
SerialNumber: serialNumber,
|
||||||
|
Subject: pkix.Name{
|
||||||
|
CommonName: options.CommonName,
|
||||||
|
Organization: options.Organization,
|
||||||
|
OrganizationalUnit: options.OrganizationalUnit,
|
||||||
|
Country: options.Country,
|
||||||
|
Province: options.Province,
|
||||||
|
Locality: options.Locality,
|
||||||
|
StreetAddress: options.StreetAddress,
|
||||||
|
PostalCode: options.PostalCode,
|
||||||
|
},
|
||||||
|
IPAddresses: options.IPAddresses,
|
||||||
|
DNSNames: options.DNSNames,
|
||||||
|
NotBefore: g.timeSource.UTCNow().Add(-g.options.Validity.Server.NotBeforeRelative),
|
||||||
|
NotAfter: g.timeSource.UTCNow().Add(g.options.Validity.Server.NotAfterRelative),
|
||||||
|
KeyUsage: x509.KeyUsageDigitalSignature,
|
||||||
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
|
||||||
|
}
|
||||||
|
var caCrt *x509.Certificate
|
||||||
|
caCrt, err = x509.ParseCertificate(ca.Certificate[0])
|
||||||
|
|
||||||
|
var derBytes []byte
|
||||||
|
if derBytes, err = x509.CreateCertificate(rand.Reader, &template, caCrt, publicKey(privateKey), ca.PrivateKey); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var privateKeyBytes []byte
|
||||||
|
if privateKeyBytes, err = x509.MarshalPKCS8PrivateKey(privateKey); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if cert, err = parseCert(derBytes, privateKeyBytes); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g generator) CACert(options GenerationOptions) (crt *tls.Certificate, err error) {
|
||||||
|
defaulters.Apply(&options)
|
||||||
|
|
||||||
|
var privateKey interface{}
|
||||||
|
var serialNumber *big.Int
|
||||||
|
if serialNumber, err = generateSerialNumber(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if privateKey, err = g.privateKey(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
template := x509.Certificate{
|
||||||
|
SerialNumber: serialNumber,
|
||||||
|
Subject: pkix.Name{
|
||||||
|
CommonName: options.CommonName,
|
||||||
|
Organization: options.Organization,
|
||||||
|
Country: options.Country,
|
||||||
|
Province: options.Province,
|
||||||
|
Locality: options.Locality,
|
||||||
|
StreetAddress: options.StreetAddress,
|
||||||
|
PostalCode: options.PostalCode,
|
||||||
|
},
|
||||||
|
IsCA: true,
|
||||||
|
NotBefore: g.timeSource.UTCNow().Add(-g.options.Validity.Server.NotBeforeRelative),
|
||||||
|
NotAfter: g.timeSource.UTCNow().Add(g.options.Validity.Server.NotAfterRelative),
|
||||||
|
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
|
||||||
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
|
||||||
|
BasicConstraintsValid: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
var derBytes []byte
|
||||||
|
if derBytes, err = x509.CreateCertificate(rand.Reader, &template, &template, publicKey(privateKey), privateKey); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var privateKeyBytes []byte
|
||||||
|
if privateKeyBytes, err = x509.MarshalPKCS8PrivateKey(privateKey); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
crt, err = parseCert(derBytes, privateKeyBytes)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateSerialNumber() (*big.Int, error) {
|
||||||
|
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
||||||
|
return rand.Int(rand.Reader, serialNumberLimit)
|
||||||
|
}
|
||||||
|
|
||||||
|
func publicKey(privateKey interface{}) interface{} {
|
||||||
|
switch k := privateKey.(type) {
|
||||||
|
case *ecdsa.PrivateKey:
|
||||||
|
return &k.PublicKey
|
||||||
|
case ed25519.PrivateKey:
|
||||||
|
return k.Public().(ed25519.PublicKey)
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseCert(derBytes []byte, privateKeyBytes []byte) (*tls.Certificate, error) {
|
||||||
|
pemEncodedPublicKey := pem.EncodeToMemory(&pem.Block{Type: certificateBlockType, Bytes: derBytes})
|
||||||
|
pemEncodedPrivateKey := pem.EncodeToMemory(&pem.Block{Type: privateKeyBlockType, Bytes: privateKeyBytes})
|
||||||
|
cert, err := tls.X509KeyPair(pemEncodedPublicKey, pemEncodedPrivateKey)
|
||||||
|
return &cert, err
|
||||||
|
}
|
79
pkg/cert/options.go
Normal file
79
pkg/cert/options.go
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
package cert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
requiredConfigKeys = []string{
|
||||||
|
publicKeyConfigKey,
|
||||||
|
privateKeyPathConfigKey,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type CurveType string
|
||||||
|
|
||||||
|
type File struct {
|
||||||
|
PublicKeyPath string
|
||||||
|
PrivateKeyPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ValidityDuration struct {
|
||||||
|
NotBeforeRelative time.Duration
|
||||||
|
NotAfterRelative time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
type ValidityByPurpose struct {
|
||||||
|
CA ValidityDuration
|
||||||
|
Server ValidityDuration
|
||||||
|
}
|
||||||
|
|
||||||
|
type Options struct {
|
||||||
|
RootCACert File
|
||||||
|
CertCachePath string
|
||||||
|
Curve CurveType
|
||||||
|
Validity ValidityByPurpose
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadFromConfig(config *viper.Viper) (Options, error) {
|
||||||
|
missingKeys := make([]string, 0)
|
||||||
|
for _, requiredKey := range requiredConfigKeys {
|
||||||
|
if !config.IsSet(requiredKey) {
|
||||||
|
missingKeys = append(missingKeys, requiredKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(missingKeys) > 0 {
|
||||||
|
return Options{}, fmt.Errorf("config keys are missing: %s", strings.Join(missingKeys, ", "))
|
||||||
|
}
|
||||||
|
|
||||||
|
config.SetDefault(certCachePathConfigKey, os.TempDir())
|
||||||
|
config.SetDefault(ecdsaCurveConfigKey, string(CurveTypeED25519))
|
||||||
|
config.SetDefault(caCertValidityNotBeforeKey, defaultCAValidityDuration)
|
||||||
|
config.SetDefault(caCertValidityNotAfterKey, defaultCAValidityDuration)
|
||||||
|
config.SetDefault(serverCertValidityNotBeforeKey, defaultServerValidityDuration)
|
||||||
|
config.SetDefault(serverCertValidityNotAfterKey, defaultServerValidityDuration)
|
||||||
|
|
||||||
|
return Options{
|
||||||
|
CertCachePath: config.GetString(certCachePathConfigKey),
|
||||||
|
Curve: CurveType(config.GetString(ecdsaCurveConfigKey)),
|
||||||
|
Validity: ValidityByPurpose{
|
||||||
|
CA: ValidityDuration{
|
||||||
|
NotBeforeRelative: config.GetDuration(caCertValidityNotBeforeKey),
|
||||||
|
NotAfterRelative: config.GetDuration(caCertValidityNotAfterKey),
|
||||||
|
},
|
||||||
|
Server: ValidityDuration{
|
||||||
|
NotBeforeRelative: config.GetDuration(serverCertValidityNotBeforeKey),
|
||||||
|
NotAfterRelative: config.GetDuration(serverCertValidityNotAfterKey),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
RootCACert: File{
|
||||||
|
PublicKeyPath: config.GetString(publicKeyConfigKey),
|
||||||
|
PrivateKeyPath: config.GetString(privateKeyPathConfigKey),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
137
pkg/cert/options_test.go
Normal file
137
pkg/cert/options_test.go
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
package cert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func readViper(cfg string) *viper.Viper {
|
||||||
|
vpr := viper.New()
|
||||||
|
vpr.SetConfigType("yaml")
|
||||||
|
if err := vpr.ReadConfig(strings.NewReader(cfg)); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return vpr
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_loadFromConfig(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
config *viper.Viper
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want Options
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Parse valid TLS configuration",
|
||||||
|
wantErr: false,
|
||||||
|
args: args{
|
||||||
|
config: readViper(`
|
||||||
|
tls:
|
||||||
|
ecdsaCurve: P256
|
||||||
|
validity:
|
||||||
|
ca:
|
||||||
|
notBeforeRelative: 17520h
|
||||||
|
notAfterRelative: 17520h
|
||||||
|
server:
|
||||||
|
NotBeforeRelative: 168h
|
||||||
|
NotAfterRelative: 168h
|
||||||
|
rootCaCert:
|
||||||
|
publicKey: ./ca.pem
|
||||||
|
privateKey: ./ca.key
|
||||||
|
certCachePath: /tmp/inetmock/
|
||||||
|
`),
|
||||||
|
},
|
||||||
|
want: Options{
|
||||||
|
RootCACert: File{
|
||||||
|
PublicKeyPath: "./ca.pem",
|
||||||
|
PrivateKeyPath: "./ca.key",
|
||||||
|
},
|
||||||
|
CertCachePath: "/tmp/inetmock/",
|
||||||
|
Curve: CurveTypeP256,
|
||||||
|
Validity: ValidityByPurpose{
|
||||||
|
CA: ValidityDuration{
|
||||||
|
NotBeforeRelative: 17520 * time.Hour,
|
||||||
|
NotAfterRelative: 17520 * time.Hour,
|
||||||
|
},
|
||||||
|
Server: ValidityDuration{
|
||||||
|
NotBeforeRelative: 168 * time.Hour,
|
||||||
|
NotAfterRelative: 168 * time.Hour,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get an error if CA public key path is missing",
|
||||||
|
args: args{
|
||||||
|
readViper(`
|
||||||
|
tls:
|
||||||
|
rootCaCert:
|
||||||
|
privateKey: ./ca.key
|
||||||
|
`),
|
||||||
|
},
|
||||||
|
want: Options{},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get an error if CA private key path is missing",
|
||||||
|
args: args{
|
||||||
|
readViper(`
|
||||||
|
tls:
|
||||||
|
rootCaCert:
|
||||||
|
publicKey: ./ca.pem
|
||||||
|
`),
|
||||||
|
},
|
||||||
|
want: Options{},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get default options if all required fields are set",
|
||||||
|
args: args{
|
||||||
|
readViper(`
|
||||||
|
tls:
|
||||||
|
rootCaCert:
|
||||||
|
publicKey: ./ca.pem
|
||||||
|
privateKey: ./ca.key
|
||||||
|
`),
|
||||||
|
},
|
||||||
|
want: Options{
|
||||||
|
RootCACert: File{
|
||||||
|
PublicKeyPath: "./ca.pem",
|
||||||
|
PrivateKeyPath: "./ca.key",
|
||||||
|
},
|
||||||
|
CertCachePath: os.TempDir(),
|
||||||
|
Curve: CurveTypeED25519,
|
||||||
|
Validity: ValidityByPurpose{
|
||||||
|
CA: ValidityDuration{
|
||||||
|
NotBeforeRelative: 17520 * time.Hour,
|
||||||
|
NotAfterRelative: 17520 * time.Hour,
|
||||||
|
},
|
||||||
|
Server: ValidityDuration{
|
||||||
|
NotBeforeRelative: 168 * time.Hour,
|
||||||
|
NotAfterRelative: 168 * time.Hour,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := loadFromConfig(tt.args.config)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("loadFromConfig() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("loadFromConfig() got = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
79
pkg/cert/pem.go
Normal file
79
pkg/cert/pem.go
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
package cert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/pem"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/baez90/inetmock/pkg/path"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
certificateBlockType = "CERTIFICATE"
|
||||||
|
privateKeyBlockType = "PRIVATE KEY"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PEM interface {
|
||||||
|
Cert() *tls.Certificate
|
||||||
|
Write(cn string, outDir string) error
|
||||||
|
Read(cn string, inDir string) error
|
||||||
|
ReadFrom(pubKeyPath, privateKeyPath string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPEM(crt *tls.Certificate) PEM {
|
||||||
|
return &pemCrt{
|
||||||
|
crt: crt,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type pemCrt struct {
|
||||||
|
crt *tls.Certificate
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pemCrt) Cert() *tls.Certificate {
|
||||||
|
return p.crt
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p pemCrt) Write(cn string, outDir string) (err error) {
|
||||||
|
|
||||||
|
var certOut *os.File
|
||||||
|
if certOut, err = os.Create(filepath.Join(outDir, fmt.Sprintf("%s.pem", cn))); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer certOut.Close()
|
||||||
|
if err = pem.Encode(certOut, &pem.Block{Type: certificateBlockType, Bytes: p.crt.Certificate[0]}); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var keyOut *os.File
|
||||||
|
if keyOut, err = os.OpenFile(filepath.Join(outDir, fmt.Sprintf("%s.key", cn)), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var privKeyBytes []byte
|
||||||
|
privKeyBytes, err = x509.MarshalPKCS8PrivateKey(p.crt.PrivateKey)
|
||||||
|
err = pem.Encode(keyOut, &pem.Block{Type: privateKeyBlockType, Bytes: privKeyBytes})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pemCrt) Read(cn string, inDir string) error {
|
||||||
|
certPath := filepath.Join(inDir, fmt.Sprintf("%s.pem", cn))
|
||||||
|
keyPath := filepath.Join(inDir, fmt.Sprintf("%s.key", cn))
|
||||||
|
|
||||||
|
return p.ReadFrom(certPath, keyPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pemCrt) ReadFrom(pubKeyPath, privateKeyPath string) (err error) {
|
||||||
|
var tlsCrt tls.Certificate
|
||||||
|
if path.FileExists(pubKeyPath) && path.FileExists(privateKeyPath) {
|
||||||
|
if tlsCrt, err = tls.LoadX509KeyPair(pubKeyPath, privateKeyPath); err == nil {
|
||||||
|
p.crt = &tlsCrt
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = errors.New("either public or private key file do not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
153
pkg/cert/store.go
Normal file
153
pkg/cert/store.go
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
package cert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/ed25519"
|
||||||
|
"crypto/elliptic"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"github.com/baez90/inetmock/pkg/logging"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ipv4Loopback = "127.0.0.1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
defaultKeyProvider = func(options Options) func() (key interface{}, err error) {
|
||||||
|
return func() (key interface{}, err error) {
|
||||||
|
return privateKeyForCurve(options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type KeyProvider func() (key interface{}, err error)
|
||||||
|
|
||||||
|
type Store interface {
|
||||||
|
CACert() *tls.Certificate
|
||||||
|
GetCertificate(serverName string, ip string) (*tls.Certificate, error)
|
||||||
|
TLSConfig() *tls.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDefaultStore(
|
||||||
|
config *viper.Viper,
|
||||||
|
logger logging.Logger,
|
||||||
|
) (Store, error) {
|
||||||
|
options, err := loadFromConfig(config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
timeSource := NewTimeSource()
|
||||||
|
return NewStore(
|
||||||
|
options,
|
||||||
|
NewFileSystemCache(options.CertCachePath, timeSource),
|
||||||
|
NewDefaultGenerator(options),
|
||||||
|
logger,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStore(
|
||||||
|
options Options,
|
||||||
|
cache Cache,
|
||||||
|
generator Generator,
|
||||||
|
logger logging.Logger,
|
||||||
|
) (Store, error) {
|
||||||
|
store := &store{
|
||||||
|
options: options,
|
||||||
|
cache: cache,
|
||||||
|
generator: generator,
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := store.loadCACert(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return store, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type store struct {
|
||||||
|
options Options
|
||||||
|
caCert *tls.Certificate
|
||||||
|
cache Cache
|
||||||
|
timeSource TimeSource
|
||||||
|
generator Generator
|
||||||
|
logger logging.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *store) TLSConfig() *tls.Config {
|
||||||
|
rootCaPool := x509.NewCertPool()
|
||||||
|
rootCaPubKey, _ := x509.ParseCertificate(s.caCert.Certificate[0])
|
||||||
|
rootCaPool.AddCert(rootCaPubKey)
|
||||||
|
|
||||||
|
return &tls.Config{
|
||||||
|
GetCertificate: func(info *tls.ClientHelloInfo) (cert *tls.Certificate, err error) {
|
||||||
|
var localIp string
|
||||||
|
if localIp, err = extractIPFromAddress(info.Conn.LocalAddr().String()); err != nil {
|
||||||
|
localIp = ipv4Loopback
|
||||||
|
}
|
||||||
|
|
||||||
|
if cert, err = s.GetCertificate(info.ServerName, localIp); err != nil {
|
||||||
|
s.logger.Error(
|
||||||
|
"error while resolving certificate",
|
||||||
|
zap.String("serverName", info.ServerName),
|
||||||
|
zap.String("localAddr", localIp),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
},
|
||||||
|
RootCAs: rootCaPool,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *store) loadCACert() (err error) {
|
||||||
|
pemCrt := NewPEM(nil)
|
||||||
|
if err = pemCrt.ReadFrom(s.options.RootCACert.PublicKeyPath, s.options.RootCACert.PrivateKeyPath); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.caCert = pemCrt.Cert()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *store) CACert() *tls.Certificate {
|
||||||
|
return s.caCert
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *store) GetCertificate(serverName string, ip string) (cert *tls.Certificate, err error) {
|
||||||
|
if crt, ok := s.cache.Get(serverName); ok {
|
||||||
|
return crt, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if cert, err = s.generator.ServerCert(GenerationOptions{
|
||||||
|
CommonName: serverName,
|
||||||
|
DNSNames: []string{serverName},
|
||||||
|
IPAddresses: []net.IP{net.ParseIP(ip)},
|
||||||
|
}, s.caCert); err == nil {
|
||||||
|
s.cache.Put(cert)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func privateKeyForCurve(options Options) (privateKey interface{}, err error) {
|
||||||
|
switch options.Curve {
|
||||||
|
case CurveTypeP224:
|
||||||
|
privateKey, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
|
||||||
|
case CurveTypeP256:
|
||||||
|
privateKey, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||||
|
case CurveTypeP384:
|
||||||
|
privateKey, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
||||||
|
case CurveTypeP521:
|
||||||
|
privateKey, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
|
||||||
|
default:
|
||||||
|
_, privateKey, err = ed25519.GenerateKey(rand.Reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
20
pkg/cert/time_source.go
Normal file
20
pkg/cert/time_source.go
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
//go:generate mockgen -source=time_source.go -destination=./../../internal/mock/cert/time_source_mock.go -package=cert_mock
|
||||||
|
|
||||||
|
package cert
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type TimeSource interface {
|
||||||
|
UTCNow() time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTimeSource() TimeSource {
|
||||||
|
return &defaultTimeSource{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type defaultTimeSource struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d defaultTimeSource) UTCNow() time.Time {
|
||||||
|
return time.Now().UTC()
|
||||||
|
}
|
43
pkg/defaulting/defaulter.go
Normal file
43
pkg/defaulting/defaulter.go
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
package defaulting
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Defaulter func(instance interface{})
|
||||||
|
|
||||||
|
type Registry interface {
|
||||||
|
Register(t reflect.Type, defaulter ...Defaulter)
|
||||||
|
Apply(instance interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() Registry {
|
||||||
|
return ®istry{
|
||||||
|
defaulters: make(map[reflect.Type][]Defaulter),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type registry struct {
|
||||||
|
defaulters map[reflect.Type][]Defaulter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *registry) Register(t reflect.Type, defaulter ...Defaulter) {
|
||||||
|
var given []Defaulter
|
||||||
|
if r, ok := r.defaulters[t]; ok {
|
||||||
|
given = r
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, d := range defaulter {
|
||||||
|
given = append(given, d)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.defaulters[t] = given
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *registry) Apply(instance interface{}) {
|
||||||
|
if defs, ok := r.defaulters[reflect.TypeOf(instance)]; ok {
|
||||||
|
for _, def := range defs {
|
||||||
|
def(instance)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
111
pkg/defaulting/defaulter_test.go
Normal file
111
pkg/defaulting/defaulter_test.go
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
package defaulting
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_registry_Apply(t *testing.T) {
|
||||||
|
type sample struct {
|
||||||
|
i int
|
||||||
|
}
|
||||||
|
type fields struct {
|
||||||
|
defaulters map[reflect.Type][]Defaulter
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
instance interface{}
|
||||||
|
}
|
||||||
|
type expect struct {
|
||||||
|
result interface{}
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
expect expect
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Expect setting a sample value",
|
||||||
|
fields: fields{
|
||||||
|
defaulters: map[reflect.Type][]Defaulter{
|
||||||
|
reflect.TypeOf(&sample{}): {func(instance interface{}) {
|
||||||
|
switch i := instance.(type) {
|
||||||
|
case *sample:
|
||||||
|
i.i = 42
|
||||||
|
}
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
instance: &sample{},
|
||||||
|
},
|
||||||
|
expect: expect{
|
||||||
|
result: &sample{
|
||||||
|
i: 42,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
r := ®istry{
|
||||||
|
defaulters: tt.fields.defaulters,
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Apply(tt.args.instance)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(tt.expect.result, tt.args.instance) {
|
||||||
|
t.Errorf("Apply() expected = %v got %v", tt.args.instance, tt.expect.result)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_registry_Register(t *testing.T) {
|
||||||
|
type sample struct {
|
||||||
|
}
|
||||||
|
type fields struct {
|
||||||
|
defaulters map[reflect.Type][]Defaulter
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
t reflect.Type
|
||||||
|
defaulter []Defaulter
|
||||||
|
}
|
||||||
|
type expect struct {
|
||||||
|
length int
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
expect expect
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "",
|
||||||
|
fields: fields{
|
||||||
|
defaulters: make(map[reflect.Type][]Defaulter),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
t: reflect.TypeOf(sample{}),
|
||||||
|
defaulter: []Defaulter{func(instance interface{}) {
|
||||||
|
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
expect: expect{
|
||||||
|
length: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
r := ®istry{
|
||||||
|
defaulters: tt.fields.defaulters,
|
||||||
|
}
|
||||||
|
r.Register(tt.args.t, tt.args.defaulter...)
|
||||||
|
|
||||||
|
if length := len(r.defaulters); length != tt.expect.length {
|
||||||
|
t.Errorf("len(r.defaulters) expect %d got %d", tt.expect.length, length)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,7 +17,9 @@ func ConfigureLogging(
|
||||||
) {
|
) {
|
||||||
loggingConfig.Level = level
|
loggingConfig.Level = level
|
||||||
loggingConfig.Development = developmentLogging
|
loggingConfig.Development = developmentLogging
|
||||||
|
if initialFields != nil {
|
||||||
loggingConfig.InitialFields = initialFields
|
loggingConfig.InitialFields = initialFields
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseLevel(levelString string) zap.AtomicLevel {
|
func ParseLevel(levelString string) zap.AtomicLevel {
|
||||||
|
@ -37,6 +39,10 @@ func ParseLevel(levelString string) zap.AtomicLevel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateLogger() (*zap.Logger, error) {
|
func CreateLogger() (Logger, error) {
|
||||||
return loggingConfig.Build()
|
if zapLogger, err := loggingConfig.Build(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return NewLogger(zapLogger), nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
166
pkg/logging/factory_test.go
Normal file
166
pkg/logging/factory_test.go
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
package logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseLevel(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
levelString string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want zap.AtomicLevel
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Test parse DEBUG level",
|
||||||
|
args: args{
|
||||||
|
levelString: "DEBUG",
|
||||||
|
},
|
||||||
|
want: zap.NewAtomicLevelAt(zap.DebugLevel),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test parse DeBuG level",
|
||||||
|
args: args{
|
||||||
|
levelString: "DeBuG",
|
||||||
|
},
|
||||||
|
want: zap.NewAtomicLevelAt(zap.DebugLevel),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test parse INFO level",
|
||||||
|
args: args{
|
||||||
|
levelString: "INFO",
|
||||||
|
},
|
||||||
|
want: zap.NewAtomicLevelAt(zap.InfoLevel),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test parse InFo level",
|
||||||
|
args: args{
|
||||||
|
levelString: "InFo",
|
||||||
|
},
|
||||||
|
want: zap.NewAtomicLevelAt(zap.InfoLevel),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test parse WARN level",
|
||||||
|
args: args{
|
||||||
|
levelString: "WARN",
|
||||||
|
},
|
||||||
|
want: zap.NewAtomicLevelAt(zap.WarnLevel),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test parse WaRn level",
|
||||||
|
args: args{
|
||||||
|
levelString: "WaRn",
|
||||||
|
},
|
||||||
|
want: zap.NewAtomicLevelAt(zap.WarnLevel),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test parse ERROR level",
|
||||||
|
args: args{
|
||||||
|
levelString: "ERROR",
|
||||||
|
},
|
||||||
|
want: zap.NewAtomicLevelAt(zap.ErrorLevel),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test parse ErRoR level",
|
||||||
|
args: args{
|
||||||
|
levelString: "ErRoR",
|
||||||
|
},
|
||||||
|
want: zap.NewAtomicLevelAt(zap.ErrorLevel),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test parse FATAL level",
|
||||||
|
args: args{
|
||||||
|
levelString: "FATAL",
|
||||||
|
},
|
||||||
|
want: zap.NewAtomicLevelAt(zap.FatalLevel),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test parse FaTaL level",
|
||||||
|
args: args{
|
||||||
|
levelString: "FaTaL",
|
||||||
|
},
|
||||||
|
want: zap.NewAtomicLevelAt(zap.FatalLevel),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Fallback to INFO level if unknown level",
|
||||||
|
args: args{
|
||||||
|
levelString: "asdf23423",
|
||||||
|
},
|
||||||
|
want: zap.NewAtomicLevelAt(zap.InfoLevel),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Fallback to INFO level if no level",
|
||||||
|
args: args{
|
||||||
|
levelString: "",
|
||||||
|
},
|
||||||
|
want: zap.NewAtomicLevelAt(zap.InfoLevel),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := ParseLevel(tt.args.levelString); !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("ParseLevel() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConfigureLogging(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
level zap.AtomicLevel
|
||||||
|
developmentLogging bool
|
||||||
|
initialFields map[string]interface{}
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Test configure defaults",
|
||||||
|
args: args{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test configure with initialFields",
|
||||||
|
args: args{
|
||||||
|
initialFields: map[string]interface{}{
|
||||||
|
"asdf": "hello, World",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test configure development logging enabled",
|
||||||
|
args: args{
|
||||||
|
developmentLogging: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test configure log level",
|
||||||
|
args: args{
|
||||||
|
level: zap.NewAtomicLevelAt(zap.FatalLevel),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
ConfigureLogging(tt.args.level, tt.args.developmentLogging, tt.args.initialFields)
|
||||||
|
if loggingConfig.Development != tt.args.developmentLogging {
|
||||||
|
t.Errorf("loggingConfig.Development = %t, want %t", loggingConfig.Development, tt.args.developmentLogging)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if loggingConfig.Level != tt.args.level {
|
||||||
|
t.Errorf("loggingConfig.Level = %v, want %v", loggingConfig.Level, tt.args.level)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tt.args.initialFields != nil && !reflect.DeepEqual(loggingConfig.InitialFields, tt.args.initialFields) {
|
||||||
|
t.Errorf("loggingConfig.InitialFields = %v, want %v", loggingConfig.InitialFields, tt.args.initialFields)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
60
pkg/logging/logger.go
Normal file
60
pkg/logging/logger.go
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
//go:generate mockgen -source=logger.go -destination=./../../internal/mock/logging/logger_mock.go -package=logging_mock
|
||||||
|
package logging
|
||||||
|
|
||||||
|
import "go.uber.org/zap"
|
||||||
|
|
||||||
|
type Logger interface {
|
||||||
|
Named(s string) Logger
|
||||||
|
With(fields ...zap.Field) Logger
|
||||||
|
Debug(msg string, fields ...zap.Field)
|
||||||
|
Info(msg string, fields ...zap.Field)
|
||||||
|
Warn(msg string, fields ...zap.Field)
|
||||||
|
Error(msg string, fields ...zap.Field)
|
||||||
|
Panic(msg string, fields ...zap.Field)
|
||||||
|
Fatal(msg string, fields ...zap.Field)
|
||||||
|
Sync() error
|
||||||
|
}
|
||||||
|
|
||||||
|
type logger struct {
|
||||||
|
underlyingLogger *zap.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLogger(underlyingLogger *zap.Logger) *logger {
|
||||||
|
return &logger{underlyingLogger: underlyingLogger}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l logger) Named(s string) Logger {
|
||||||
|
return NewLogger(l.underlyingLogger.Named(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l logger) With(fields ...zap.Field) Logger {
|
||||||
|
return NewLogger(l.underlyingLogger.With(fields...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l logger) Debug(msg string, fields ...zap.Field) {
|
||||||
|
l.underlyingLogger.Debug(msg, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l logger) Info(msg string, fields ...zap.Field) {
|
||||||
|
l.underlyingLogger.Info(msg, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l logger) Warn(msg string, fields ...zap.Field) {
|
||||||
|
l.underlyingLogger.Warn(msg, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l logger) Error(msg string, fields ...zap.Field) {
|
||||||
|
l.underlyingLogger.Error(msg, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l logger) Panic(msg string, fields ...zap.Field) {
|
||||||
|
l.underlyingLogger.Panic(msg, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l logger) Fatal(msg string, fields ...zap.Field) {
|
||||||
|
l.underlyingLogger.Fatal(msg, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l logger) Sync() error {
|
||||||
|
return l.underlyingLogger.Sync()
|
||||||
|
}
|
|
@ -2,11 +2,10 @@ package path
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func WorkingDirectory() (cwd string) {
|
func WorkingDirectory() (cwd string) {
|
||||||
cwd, _ = filepath.Abs(filepath.Dir(os.Args[0]))
|
cwd, _ = os.Getwd()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
module github.com/baez90/inetmock/pkg/plugins/dns_mock
|
|
||||||
|
|
||||||
go 1.14
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/baez90/inetmock v0.0.1
|
|
||||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
|
||||||
github.com/miekg/dns v1.1.29
|
|
||||||
github.com/mitchellh/mapstructure v1.2.2 // indirect
|
|
||||||
github.com/pelletier/go-toml v1.7.0 // indirect
|
|
||||||
github.com/spf13/afero v1.2.2 // indirect
|
|
||||||
github.com/spf13/cast v1.3.1 // indirect
|
|
||||||
github.com/spf13/cobra v1.0.0 // indirect
|
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
|
||||||
github.com/spf13/viper v1.6.3
|
|
||||||
go.uber.org/zap v1.14.1
|
|
||||||
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa // indirect
|
|
||||||
golang.org/x/text v0.3.2 // indirect
|
|
||||||
gopkg.in/ini.v1 v1.55.0 // indirect
|
|
||||||
)
|
|
||||||
|
|
||||||
replace github.com/baez90/inetmock v0.0.1 => ../../../
|
|
|
@ -1,3 +0,0 @@
|
||||||
module github.com/baez90/inetmock/pkg/plugins
|
|
||||||
|
|
||||||
go 1.14
|
|
|
@ -1,21 +0,0 @@
|
||||||
module github.com/baez90/inetmock/pkg/plugins/http_mock
|
|
||||||
|
|
||||||
go 1.14
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/baez90/inetmock v0.0.1
|
|
||||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
|
||||||
github.com/mitchellh/mapstructure v1.2.2 // indirect
|
|
||||||
github.com/pelletier/go-toml v1.7.0 // indirect
|
|
||||||
github.com/spf13/afero v1.2.2 // indirect
|
|
||||||
github.com/spf13/cast v1.3.1 // indirect
|
|
||||||
github.com/spf13/cobra v1.0.0 // indirect
|
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
|
||||||
github.com/spf13/viper v1.6.3
|
|
||||||
go.uber.org/zap v1.14.1
|
|
||||||
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa // indirect
|
|
||||||
golang.org/x/text v0.3.2 // indirect
|
|
||||||
gopkg.in/ini.v1 v1.55.0 // indirect
|
|
||||||
)
|
|
||||||
|
|
||||||
replace github.com/baez90/inetmock v0.0.1 => ../../../
|
|
|
@ -1,89 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"github.com/baez90/inetmock/internal/config"
|
|
||||||
"github.com/baez90/inetmock/pkg/path"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"net/http"
|
|
||||||
"path/filepath"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
name = "http_mock"
|
|
||||||
)
|
|
||||||
|
|
||||||
type httpHandler struct {
|
|
||||||
logger *zap.Logger
|
|
||||||
router *RegexpHandler
|
|
||||||
server *http.Server
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *httpHandler) Run(config config.HandlerConfig) {
|
|
||||||
options := loadFromConfig(config.Options())
|
|
||||||
addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port())
|
|
||||||
p.server = &http.Server{Addr: addr, Handler: p.router}
|
|
||||||
p.logger = p.logger.With(
|
|
||||||
zap.String("address", addr),
|
|
||||||
)
|
|
||||||
|
|
||||||
for _, rule := range options.Rules {
|
|
||||||
p.setupRoute(rule)
|
|
||||||
}
|
|
||||||
|
|
||||||
go p.startServer()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *httpHandler) Shutdown(wg *sync.WaitGroup) {
|
|
||||||
if err := p.server.Close(); err != nil {
|
|
||||||
p.logger.Error(
|
|
||||||
"failed to shutdown HTTP server",
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
wg.Done()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *httpHandler) startServer() {
|
|
||||||
if err := p.server.ListenAndServe(); err != nil {
|
|
||||||
p.logger.Error(
|
|
||||||
"failed to start http listener",
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *httpHandler) setupRoute(rule targetRule) {
|
|
||||||
p.logger.Info(
|
|
||||||
"setup routing",
|
|
||||||
zap.String("route", rule.Pattern().String()),
|
|
||||||
zap.String("response", rule.Response()),
|
|
||||||
)
|
|
||||||
|
|
||||||
p.router.Handler(rule.Pattern(), createHandlerForTarget(p.logger, rule.response))
|
|
||||||
}
|
|
||||||
|
|
||||||
func createHandlerForTarget(logger *zap.Logger, targetPath string) http.Handler {
|
|
||||||
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
|
||||||
targetFilePath := filepath.Join(path.WorkingDirectory(), targetPath)
|
|
||||||
|
|
||||||
headerWriter := &bytes.Buffer{}
|
|
||||||
request.Header.Write(headerWriter)
|
|
||||||
|
|
||||||
logger.Info(
|
|
||||||
"Handling request",
|
|
||||||
zap.String("source", request.RemoteAddr),
|
|
||||||
zap.String("host", request.Host),
|
|
||||||
zap.String("method", request.Method),
|
|
||||||
zap.String("protocol", request.Proto),
|
|
||||||
zap.String("path", request.RequestURI),
|
|
||||||
zap.String("response", targetFilePath),
|
|
||||||
zap.Reflect("headers", request.Header),
|
|
||||||
)
|
|
||||||
|
|
||||||
http.ServeFile(writer, request, targetFilePath)
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ipExtractionRegex = regexp.MustCompile(`(.+):\d{1,5}$`)
|
|
||||||
)
|
|
||||||
|
|
||||||
func extractIPFromAddress(addr string) (string, error) {
|
|
||||||
matches := ipExtractionRegex.FindAllStringSubmatch(addr, -1)
|
|
||||||
if len(matches) > 0 && len(matches[0]) >= 1 {
|
|
||||||
return strings.Trim(matches[0][1], "[]"), nil
|
|
||||||
} else {
|
|
||||||
return "", fmt.Errorf("failed to extract IP address from addr %s", addr)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,203 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/tls"
|
|
||||||
"crypto/x509"
|
|
||||||
"crypto/x509/pkix"
|
|
||||||
"fmt"
|
|
||||||
"github.com/baez90/inetmock/pkg/path"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"math/big"
|
|
||||||
"net"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
type keyProvider func() (key interface{}, err error)
|
|
||||||
|
|
||||||
type certStore struct {
|
|
||||||
options *tlsOptions
|
|
||||||
keyProvider keyProvider
|
|
||||||
caCert *x509.Certificate
|
|
||||||
caPrivateKey interface{}
|
|
||||||
certCache map[string]*tls.Certificate
|
|
||||||
timeSourceInstance timeSource
|
|
||||||
logger *zap.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cs *certStore) timeSource() timeSource {
|
|
||||||
if cs.timeSourceInstance == nil {
|
|
||||||
cs.timeSourceInstance = createTimeSource()
|
|
||||||
}
|
|
||||||
return cs.timeSourceInstance
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cs *certStore) initCaCert() (err error) {
|
|
||||||
if path.FileExists(cs.options.rootCaCert.publicKeyPath) && path.FileExists(cs.options.rootCaCert.privateKeyPath) {
|
|
||||||
var tlsCert tls.Certificate
|
|
||||||
if tlsCert, err = tls.LoadX509KeyPair(cs.options.rootCaCert.publicKeyPath, cs.options.rootCaCert.privateKeyPath); err != nil {
|
|
||||||
return
|
|
||||||
} else if len(tlsCert.Certificate) > 0 {
|
|
||||||
cs.caPrivateKey = tlsCert.PrivateKey
|
|
||||||
cs.caCert, err = x509.ParseCertificate(tlsCert.Certificate[0])
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cs.caCert, cs.caPrivateKey, err = cs.generateCaCert()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cs *certStore) initProvider() {
|
|
||||||
if cs.keyProvider == nil {
|
|
||||||
cs.keyProvider = func() (key interface{}, err error) {
|
|
||||||
return privateKeyForCurve(cs.options)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cs *certStore) generateCaCert() (pubKey *x509.Certificate, privateKey interface{}, err error) {
|
|
||||||
cs.initProvider()
|
|
||||||
timeSource := cs.timeSource()
|
|
||||||
var serialNumber *big.Int
|
|
||||||
if serialNumber, err = generateSerialNumber(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if privateKey, err = cs.keyProvider(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
template := x509.Certificate{
|
|
||||||
SerialNumber: serialNumber,
|
|
||||||
Subject: pkix.Name{
|
|
||||||
Organization: []string{"INetMock"},
|
|
||||||
Country: []string{"US"},
|
|
||||||
Province: []string{""},
|
|
||||||
Locality: []string{"San Francisco"},
|
|
||||||
StreetAddress: []string{"Golden Gate Bridge"},
|
|
||||||
PostalCode: []string{"94016"},
|
|
||||||
},
|
|
||||||
IsCA: true,
|
|
||||||
NotBefore: timeSource.UTCNow().Add(-cs.options.validity.ca.notBeforeRelative),
|
|
||||||
NotAfter: timeSource.UTCNow().Add(cs.options.validity.ca.notAfterRelative),
|
|
||||||
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
|
|
||||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
|
|
||||||
BasicConstraintsValid: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
var derBytes []byte
|
|
||||||
if derBytes, err = x509.CreateCertificate(rand.Reader, &template, &template, publicKey(privateKey), privateKey); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pubKey, err = x509.ParseCertificate(derBytes)
|
|
||||||
|
|
||||||
if err = writePublicKey(cs.options.rootCaCert.publicKeyPath, derBytes); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var privateKeyBytes []byte
|
|
||||||
if privateKeyBytes, err = x509.MarshalPKCS8PrivateKey(privateKey); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = writePrivateKey(cs.options.rootCaCert.privateKeyPath, privateKeyBytes); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cs *certStore) getCertificate(serverName string, ip string) (cert *tls.Certificate, err error) {
|
|
||||||
if cert, ok := cs.certCache[serverName]; ok {
|
|
||||||
return cert, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
certPath := filepath.Join(cs.options.certCachePath, fmt.Sprintf("%s.pem", serverName))
|
|
||||||
keyPath := filepath.Join(cs.options.certCachePath, fmt.Sprintf("%s.key", serverName))
|
|
||||||
|
|
||||||
if path.FileExists(certPath) && path.FileExists(keyPath) {
|
|
||||||
if tlsCert, loadErr := tls.LoadX509KeyPair(certPath, keyPath); loadErr == nil {
|
|
||||||
cs.certCache[serverName] = &tlsCert
|
|
||||||
x509Cert, err := x509.ParseCertificate(tlsCert.Certificate[0])
|
|
||||||
if err == nil && !certShouldBeRenewed(cs.timeSource(), x509Cert) {
|
|
||||||
return &tlsCert, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if cert, err = cs.generateDomainCert(serverName, ip); err == nil {
|
|
||||||
cs.certCache[serverName] = cert
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cs *certStore) generateDomainCert(
|
|
||||||
serverName string,
|
|
||||||
localIp string,
|
|
||||||
) (cert *tls.Certificate, err error) {
|
|
||||||
cs.initProvider()
|
|
||||||
|
|
||||||
if cs.caCert == nil {
|
|
||||||
if err = cs.initCaCert(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var serialNumber *big.Int
|
|
||||||
if serialNumber, err = generateSerialNumber(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var privateKey interface{}
|
|
||||||
if privateKey, err = cs.keyProvider(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
notBefore := cs.timeSource().UTCNow().Add(-cs.options.validity.domain.notBeforeRelative)
|
|
||||||
notAfter := cs.timeSource().UTCNow().Add(cs.options.validity.domain.notAfterRelative)
|
|
||||||
|
|
||||||
cs.logger.Info(
|
|
||||||
"generate domain certificate",
|
|
||||||
zap.Time("notBefore", notBefore),
|
|
||||||
zap.Time("notAfter", notAfter),
|
|
||||||
)
|
|
||||||
|
|
||||||
template := x509.Certificate{
|
|
||||||
SerialNumber: serialNumber,
|
|
||||||
Subject: pkix.Name{
|
|
||||||
Organization: []string{"INetMock"},
|
|
||||||
},
|
|
||||||
IPAddresses: []net.IP{net.ParseIP(localIp)},
|
|
||||||
DNSNames: []string{serverName},
|
|
||||||
NotBefore: notBefore,
|
|
||||||
NotAfter: notAfter,
|
|
||||||
KeyUsage: x509.KeyUsageDigitalSignature,
|
|
||||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
|
|
||||||
}
|
|
||||||
|
|
||||||
var derBytes []byte
|
|
||||||
if derBytes, err = x509.CreateCertificate(rand.Reader, &template, cs.caCert, publicKey(privateKey), cs.caPrivateKey); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = writePublicKey(filepath.Join(cs.options.certCachePath, fmt.Sprintf("%s.pem", serverName)), derBytes); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var privateKeyBytes []byte
|
|
||||||
if privateKeyBytes, err = x509.MarshalPKCS8PrivateKey(privateKey); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if cert, err = parseCert(derBytes, privateKeyBytes); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = writePrivateKey(filepath.Join(cs.options.certCachePath, fmt.Sprintf("%s.key", serverName)), privateKeyBytes); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,211 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/tls"
|
|
||||||
"crypto/x509"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_generateCaCert(t *testing.T) {
|
|
||||||
tmpDir, err := ioutil.TempDir(os.TempDir(), "*-inetmock")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("failed to create temp dir %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
options := &tlsOptions{
|
|
||||||
ecdsaCurve: "P256",
|
|
||||||
rootCaCert: cert{
|
|
||||||
publicKeyPath: filepath.Join(tmpDir, "localhost.pem"),
|
|
||||||
privateKeyPath: filepath.Join(tmpDir, "localhost.key"),
|
|
||||||
},
|
|
||||||
validity: validity{
|
|
||||||
ca: certValidity{
|
|
||||||
notBeforeRelative: time.Hour * 24 * 30,
|
|
||||||
notAfterRelative: time.Hour * 24 * 30,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
certStore := certStore{
|
|
||||||
options: options,
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
_ = os.Remove(tmpDir)
|
|
||||||
}()
|
|
||||||
|
|
||||||
_, _, err = certStore.generateCaCert()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("failed to generate CA cert %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = os.Stat(options.rootCaCert.publicKeyPath); err != nil {
|
|
||||||
t.Errorf("cert file was not created")
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = os.Stat(options.rootCaCert.privateKeyPath); err != nil {
|
|
||||||
t.Errorf("cert file was not created")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_generateDomainCert(t *testing.T) {
|
|
||||||
|
|
||||||
tmpDir, err := ioutil.TempDir(os.TempDir(), "*-inetmock")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("failed to create temp dir %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
_ = os.Remove(tmpDir)
|
|
||||||
}()
|
|
||||||
|
|
||||||
caTlsCert, _ := loadPEMCert(testCaCrt, testCaKey)
|
|
||||||
caCert, _ := x509.ParseCertificate(caTlsCert.Certificate[0])
|
|
||||||
|
|
||||||
options := &tlsOptions{
|
|
||||||
ecdsaCurve: "P256",
|
|
||||||
certCachePath: tmpDir,
|
|
||||||
validity: validity{
|
|
||||||
domain: certValidity{
|
|
||||||
notAfterRelative: time.Hour * 24 * 30,
|
|
||||||
notBeforeRelative: time.Hour * 24 * 30,
|
|
||||||
},
|
|
||||||
ca: certValidity{
|
|
||||||
notAfterRelative: time.Hour * 24 * 30,
|
|
||||||
notBeforeRelative: time.Hour * 24 * 30,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
logger, _ := zap.NewDevelopment()
|
|
||||||
|
|
||||||
certStore := certStore{
|
|
||||||
options: options,
|
|
||||||
caCert: caCert,
|
|
||||||
logger: logger,
|
|
||||||
caPrivateKey: caTlsCert.PrivateKey,
|
|
||||||
}
|
|
||||||
|
|
||||||
type args struct {
|
|
||||||
domain string
|
|
||||||
ip string
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Test create google.com cert",
|
|
||||||
args: args{
|
|
||||||
domain: "google.com",
|
|
||||||
ip: "127.0.0.1",
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Test create golem.de cert",
|
|
||||||
args: args{
|
|
||||||
domain: "golem.de",
|
|
||||||
ip: "127.0.0.1",
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Test create golem.de cert with any IP address",
|
|
||||||
args: args{
|
|
||||||
domain: "golem.de",
|
|
||||||
ip: "10.10.0.10",
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
if domainCert, err := certStore.generateDomainCert(
|
|
||||||
tt.args.domain,
|
|
||||||
tt.args.ip,
|
|
||||||
); (err != nil) != tt.wantErr || reflect.DeepEqual(domainCert, tls.Certificate{}) {
|
|
||||||
t.Errorf("generateDomainCert() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_certStore_initCaCert(t *testing.T) {
|
|
||||||
|
|
||||||
tmpDir, err := ioutil.TempDir(os.TempDir(), "*-inetmock")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("failed to create temp dir %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
_ = os.Remove(tmpDir)
|
|
||||||
}()
|
|
||||||
|
|
||||||
caCertPath := filepath.Join(tmpDir, "cacert.pem")
|
|
||||||
caKeyPath := filepath.Join(tmpDir, "cacert.key")
|
|
||||||
|
|
||||||
if err := ioutil.WriteFile(caCertPath, testCaCrt, 0600); err != nil {
|
|
||||||
t.Errorf("failed to write cacert.pem %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err := ioutil.WriteFile(caKeyPath, testCaKey, 0600); err != nil {
|
|
||||||
t.Errorf("failed to write cacert.key %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type fields struct {
|
|
||||||
options *tlsOptions
|
|
||||||
caCert *x509.Certificate
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
fields fields
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Init CA cert from file",
|
|
||||||
wantErr: false,
|
|
||||||
fields: fields{
|
|
||||||
options: &tlsOptions{
|
|
||||||
rootCaCert: cert{
|
|
||||||
publicKeyPath: caCertPath,
|
|
||||||
privateKeyPath: caKeyPath,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Init CA with new cert",
|
|
||||||
wantErr: false,
|
|
||||||
fields: fields{
|
|
||||||
options: &tlsOptions{
|
|
||||||
rootCaCert: cert{
|
|
||||||
publicKeyPath: filepath.Join(tmpDir, "nonexistent.pem"),
|
|
||||||
privateKeyPath: filepath.Join(tmpDir, "nonexistent.key"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
cs := &certStore{
|
|
||||||
options: tt.fields.options,
|
|
||||||
caCert: tt.fields.caCert,
|
|
||||||
}
|
|
||||||
if err := cs.initCaCert(); (err != nil) != tt.wantErr || cs.caCert == nil {
|
|
||||||
t.Errorf("initCaCert() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,106 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/ecdsa"
|
|
||||||
"crypto/ed25519"
|
|
||||||
"crypto/elliptic"
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/tls"
|
|
||||||
"crypto/x509"
|
|
||||||
"encoding/pem"
|
|
||||||
"math/big"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
type curveType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
certificateBlockType = "CERTIFICATE"
|
|
||||||
privateKeyBlockType = "PRIVATE KEY"
|
|
||||||
|
|
||||||
curveTypeP224 curveType = "P224"
|
|
||||||
curveTypeP256 curveType = "P256"
|
|
||||||
curveTypeP384 curveType = "P384"
|
|
||||||
curveTypeP521 curveType = "P521"
|
|
||||||
curveTypeED25519 curveType = "ED25519"
|
|
||||||
)
|
|
||||||
|
|
||||||
func loadPEMCert(certPEMBytes []byte, keyPEMBytes []byte) (*tls.Certificate, error) {
|
|
||||||
cert, err := tls.X509KeyPair(certPEMBytes, keyPEMBytes)
|
|
||||||
return &cert, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseCert(derBytes []byte, privateKeyBytes []byte) (*tls.Certificate, error) {
|
|
||||||
pemEncodedPublicKey := pem.EncodeToMemory(&pem.Block{Type: certificateBlockType, Bytes: derBytes})
|
|
||||||
pemEncodedPrivateKey := pem.EncodeToMemory(&pem.Block{Type: privateKeyBlockType, Bytes: privateKeyBytes})
|
|
||||||
cert, err := tls.X509KeyPair(pemEncodedPublicKey, pemEncodedPrivateKey)
|
|
||||||
return &cert, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func writePublicKey(crtOutPath string, derBytes []byte) (err error) {
|
|
||||||
var certOut *os.File
|
|
||||||
if certOut, err = os.Create(crtOutPath); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err = pem.Encode(certOut, &pem.Block{Type: certificateBlockType, Bytes: derBytes}); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = certOut.Close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func writePrivateKey(keyOutPath string, privateKeyBytes []byte) (err error) {
|
|
||||||
var keyOut *os.File
|
|
||||||
if keyOut, err = os.OpenFile(keyOutPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = pem.Encode(keyOut, &pem.Block{Type: privateKeyBlockType, Bytes: privateKeyBytes}); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = keyOut.Close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func certShouldBeRenewed(timeSource timeSource, cert *x509.Certificate) bool {
|
|
||||||
lifetime := cert.NotAfter.Sub(cert.NotBefore)
|
|
||||||
// if the cert is closer to the end of the lifetime than lifetime/2 it should be renewed
|
|
||||||
if cert.NotAfter.Sub(timeSource.UTCNow()) < lifetime/4 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateSerialNumber() (*big.Int, error) {
|
|
||||||
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
|
||||||
return rand.Int(rand.Reader, serialNumberLimit)
|
|
||||||
}
|
|
||||||
|
|
||||||
func privateKeyForCurve(options *tlsOptions) (privateKey interface{}, err error) {
|
|
||||||
switch options.ecdsaCurve {
|
|
||||||
case "P224":
|
|
||||||
privateKey, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
|
|
||||||
case "P256":
|
|
||||||
privateKey, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
|
||||||
case "P384":
|
|
||||||
privateKey, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
|
||||||
case "P521":
|
|
||||||
privateKey, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
|
|
||||||
default:
|
|
||||||
_, privateKey, err = ed25519.GenerateKey(rand.Reader)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func publicKey(privateKey interface{}) interface{} {
|
|
||||||
switch k := privateKey.(type) {
|
|
||||||
case *ecdsa.PrivateKey:
|
|
||||||
return &k.PublicKey
|
|
||||||
case ed25519.PrivateKey:
|
|
||||||
return k.Public().(ed25519.PublicKey)
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/x509"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type testTimeSource struct {
|
|
||||||
nowValue time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t testTimeSource) UTCNow() time.Time {
|
|
||||||
return t.nowValue
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_certShouldBeRenewed(t *testing.T) {
|
|
||||||
type args struct {
|
|
||||||
timeSource timeSource
|
|
||||||
cert *x509.Certificate
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
want bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Detect cert is expired",
|
|
||||||
want: true,
|
|
||||||
args: args{
|
|
||||||
cert: &x509.Certificate{
|
|
||||||
NotAfter: time.Now().UTC().Add(1 * time.Hour),
|
|
||||||
NotBefore: time.Now().UTC().Add(-1 * time.Hour),
|
|
||||||
},
|
|
||||||
timeSource: testTimeSource{
|
|
||||||
nowValue: time.Now().UTC().Add(2 * time.Hour),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Detect cert should be renewed",
|
|
||||||
want: true,
|
|
||||||
args: args{
|
|
||||||
cert: &x509.Certificate{
|
|
||||||
NotAfter: time.Now().UTC().Add(1 * time.Hour),
|
|
||||||
NotBefore: time.Now().UTC().Add(-1 * time.Hour),
|
|
||||||
},
|
|
||||||
timeSource: testTimeSource{
|
|
||||||
nowValue: time.Now().UTC().Add(45 * time.Minute),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Detect cert shouldn't be renewed",
|
|
||||||
want: false,
|
|
||||||
args: args{
|
|
||||||
cert: &x509.Certificate{
|
|
||||||
NotAfter: time.Now().UTC().Add(1 * time.Hour),
|
|
||||||
NotBefore: time.Now().UTC().Add(-1 * time.Hour),
|
|
||||||
},
|
|
||||||
timeSource: testTimeSource{
|
|
||||||
nowValue: time.Now().UTC().Add(25 * time.Minute),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
if got := certShouldBeRenewed(tt.args.timeSource, tt.args.cert); got != tt.want {
|
|
||||||
t.Errorf("certShouldBeRenewed() = %v, want %v", got, tt.want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,112 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
generateCACertOutPath = "cert-out"
|
|
||||||
generateCAKeyOutPath = "key-out"
|
|
||||||
generateCACurveName = "curve"
|
|
||||||
generateCANotBeforeRelative = "not-before"
|
|
||||||
generateCANotAfterRelative = "not-after"
|
|
||||||
)
|
|
||||||
|
|
||||||
func generateCACmd(logger *zap.Logger) *cobra.Command {
|
|
||||||
cmd := &cobra.Command{
|
|
||||||
Use: "generate-ca",
|
|
||||||
Short: "Generate a new CA certificate and corresponding key",
|
|
||||||
Long: ``,
|
|
||||||
Run: runGenerateCA(logger),
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd.Flags().String(generateCACertOutPath, "", "Path where CA cert file should be stored")
|
|
||||||
cmd.Flags().String(generateCAKeyOutPath, "", "Path where CA key file should be stored")
|
|
||||||
cmd.Flags().String(generateCACurveName, "", "Name of the curve to use, if empty ED25519 is used, other valid values are [P224, P256,P384,P521]")
|
|
||||||
cmd.Flags().Duration(generateCANotBeforeRelative, 17520*time.Hour, "Relative time value since when in the past the CA certificate should be valid. The value has a time unit, the greatest time unit is h for hour.")
|
|
||||||
cmd.Flags().Duration(generateCANotAfterRelative, 17520*time.Hour, "Relative time value until when in the future the CA certificate should be valid. The value has a time unit, the greatest time unit is h for hour.")
|
|
||||||
|
|
||||||
return cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
func getDurationFlag(cmd *cobra.Command, flagName string, logger *zap.Logger) (val time.Duration, err error) {
|
|
||||||
if val, err = cmd.Flags().GetDuration(flagName); err != nil {
|
|
||||||
logger.Error(
|
|
||||||
"failed to parse parse flag",
|
|
||||||
zap.String("flag", flagName),
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func getStringFlag(cmd *cobra.Command, flagName string, logger *zap.Logger) (val string, err error) {
|
|
||||||
if val, err = cmd.Flags().GetString(flagName); err != nil {
|
|
||||||
logger.Error(
|
|
||||||
"failed to parse parse flag",
|
|
||||||
zap.String("flag", flagName),
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func runGenerateCA(logger *zap.Logger) func(cmd *cobra.Command, args []string) {
|
|
||||||
return func(cmd *cobra.Command, args []string) {
|
|
||||||
var certOutPath, keyOutPath, curveName string
|
|
||||||
var notBefore, notAfter time.Duration
|
|
||||||
var err error
|
|
||||||
|
|
||||||
if certOutPath, err = getStringFlag(cmd, generateCACertOutPath, logger); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if keyOutPath, err = getStringFlag(cmd, generateCAKeyOutPath, logger); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if curveName, err = getStringFlag(cmd, generateCACurveName, logger); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if notBefore, err = getDurationFlag(cmd, generateCANotBeforeRelative, logger); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if notAfter, err = getDurationFlag(cmd, generateCANotAfterRelative, logger); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
logger := logger.With(
|
|
||||||
zap.String(generateCACurveName, curveName),
|
|
||||||
zap.String(generateCACertOutPath, certOutPath),
|
|
||||||
zap.String(generateCAKeyOutPath, keyOutPath),
|
|
||||||
)
|
|
||||||
|
|
||||||
certStore := certStore{
|
|
||||||
options: &tlsOptions{
|
|
||||||
ecdsaCurve: curveType(curveName),
|
|
||||||
validity: validity{
|
|
||||||
ca: certValidity{
|
|
||||||
notAfterRelative: notAfter,
|
|
||||||
notBeforeRelative: notBefore,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
rootCaCert: cert{
|
|
||||||
publicKeyPath: certOutPath,
|
|
||||||
privateKeyPath: keyOutPath,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, _, err := certStore.generateCaCert(); err != nil {
|
|
||||||
logger.Error(
|
|
||||||
"failed to generate CA cert",
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
logger.Info("Successfully generated CA cert")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
module github.com/baez90/inetmock/pkg/plugins/tls_interceptor
|
|
||||||
|
|
||||||
go 1.14
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/baez90/inetmock v0.0.1
|
|
||||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
|
||||||
github.com/mitchellh/mapstructure v1.2.2 // indirect
|
|
||||||
github.com/pelletier/go-toml v1.7.0 // indirect
|
|
||||||
github.com/spf13/afero v1.2.2 // indirect
|
|
||||||
github.com/spf13/cast v1.3.1 // indirect
|
|
||||||
github.com/spf13/cobra v1.0.0
|
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
|
||||||
github.com/spf13/viper v1.6.3
|
|
||||||
go.uber.org/zap v1.14.1
|
|
||||||
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa // indirect
|
|
||||||
golang.org/x/text v0.3.2 // indirect
|
|
||||||
gopkg.in/ini.v1 v1.55.0 // indirect
|
|
||||||
)
|
|
||||||
|
|
||||||
replace github.com/baez90/inetmock v0.0.1 => ../../../
|
|
|
@ -1,78 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
certCachePathConfigKey = "certCachePath"
|
|
||||||
ecdsaCurveConfigKey = "ecdsaCurve"
|
|
||||||
targetIpAddressConfigKey = "target.ipAddress"
|
|
||||||
targetPortConfigKey = "target.port"
|
|
||||||
publicKeyConfigKey = "rootCaCert.publicKey"
|
|
||||||
privateKeyPathConfigKey = "rootCaCert.privateKey"
|
|
||||||
caCertValidityNotBeforeKey = "validity.ca.notBeforeRelative"
|
|
||||||
caCertValidityNotAfterKey = "validity.ca.notAfterRelative"
|
|
||||||
domainCertValidityNotBeforeKey = "validity.domain.notBeforeRelative"
|
|
||||||
domainCertValidityNotAfterKey = "validity.domain.notAfterRelative"
|
|
||||||
)
|
|
||||||
|
|
||||||
type cert struct {
|
|
||||||
publicKeyPath string
|
|
||||||
privateKeyPath string
|
|
||||||
}
|
|
||||||
|
|
||||||
type certValidity struct {
|
|
||||||
notBeforeRelative time.Duration
|
|
||||||
notAfterRelative time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
type validity struct {
|
|
||||||
ca certValidity
|
|
||||||
domain certValidity
|
|
||||||
}
|
|
||||||
|
|
||||||
type redirectionTarget struct {
|
|
||||||
ipAddress string
|
|
||||||
port uint16
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rt redirectionTarget) address() string {
|
|
||||||
return fmt.Sprintf("%s:%d", rt.ipAddress, rt.port)
|
|
||||||
}
|
|
||||||
|
|
||||||
type tlsOptions struct {
|
|
||||||
rootCaCert cert
|
|
||||||
certCachePath string
|
|
||||||
redirectionTarget redirectionTarget
|
|
||||||
ecdsaCurve curveType
|
|
||||||
validity validity
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadFromConfig(config *viper.Viper) *tlsOptions {
|
|
||||||
|
|
||||||
return &tlsOptions{
|
|
||||||
certCachePath: config.GetString(certCachePathConfigKey),
|
|
||||||
ecdsaCurve: curveType(config.GetString(ecdsaCurveConfigKey)),
|
|
||||||
redirectionTarget: redirectionTarget{
|
|
||||||
ipAddress: config.GetString(targetIpAddressConfigKey),
|
|
||||||
port: uint16(config.GetInt(targetPortConfigKey)),
|
|
||||||
},
|
|
||||||
validity: validity{
|
|
||||||
ca: certValidity{
|
|
||||||
notBeforeRelative: config.GetDuration(caCertValidityNotBeforeKey),
|
|
||||||
notAfterRelative: config.GetDuration(caCertValidityNotAfterKey),
|
|
||||||
},
|
|
||||||
domain: certValidity{
|
|
||||||
notBeforeRelative: config.GetDuration(domainCertValidityNotBeforeKey),
|
|
||||||
notAfterRelative: config.GetDuration(domainCertValidityNotAfterKey),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
rootCaCert: cert{
|
|
||||||
publicKeyPath: config.GetString(publicKeyConfigKey),
|
|
||||||
privateKeyPath: config.GetString(privateKeyPathConfigKey),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
testCaCrt []byte
|
|
||||||
testCaKey []byte
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
tmpDir, err := ioutil.TempDir(os.TempDir(), "*-inetmock")
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("failed to create temp dir %v", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
options := &tlsOptions{
|
|
||||||
ecdsaCurve: "P256",
|
|
||||||
rootCaCert: cert{
|
|
||||||
publicKeyPath: filepath.Join(tmpDir, "localhost.pem"),
|
|
||||||
privateKeyPath: filepath.Join(tmpDir, "localhost.key"),
|
|
||||||
},
|
|
||||||
validity: validity{
|
|
||||||
ca: certValidity{
|
|
||||||
notBeforeRelative: time.Hour * 24 * 30,
|
|
||||||
notAfterRelative: time.Hour * 24 * 30,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
certStore := certStore{
|
|
||||||
options: options,
|
|
||||||
keyProvider: func() (key interface{}, err error) {
|
|
||||||
return privateKeyForCurve(options)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
_ = os.Remove(tmpDir)
|
|
||||||
}()
|
|
||||||
|
|
||||||
_, _, err = certStore.generateCaCert()
|
|
||||||
|
|
||||||
testCaCrt, _ = ioutil.ReadFile(options.rootCaCert.publicKeyPath)
|
|
||||||
testCaKey, _ = ioutil.ReadFile(options.rootCaCert.privateKeyPath)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("failed to generate CA cert %v", err))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type timeSource interface {
|
|
||||||
UTCNow() time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
func createTimeSource() timeSource {
|
|
||||||
return &defaultTimeSource{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type defaultTimeSource struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d defaultTimeSource) UTCNow() time.Time {
|
|
||||||
return time.Now().UTC()
|
|
||||||
}
|
|
|
@ -7,17 +7,20 @@ GO_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s"
|
||||||
GO_CONTAINER_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s" -a -installsuffix cgo
|
GO_CONTAINER_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s" -a -installsuffix cgo
|
||||||
GO_DEBUG_BUILD_ARGS = -buildmode=plugin -gcflags "all=-N -l"
|
GO_DEBUG_BUILD_ARGS = -buildmode=plugin -gcflags "all=-N -l"
|
||||||
PLUGIN_NAME = $(shell basename $(DIR)).so
|
PLUGIN_NAME = $(shell basename $(DIR)).so
|
||||||
OUT_DIR = $(DIR)../../../plugins
|
OUT_DIR = $(DIR)../../
|
||||||
DEBUG_PORT = 2345
|
DEBUG_PORT = 2345
|
||||||
|
|
||||||
.PHONY: deps format compile test cli-cover-report html-cover-report
|
.PHONY: deps update-deps format compile test cli-cover-report html-cover-report
|
||||||
|
|
||||||
all: format compile test
|
all: format compile test
|
||||||
|
|
||||||
deps:
|
deps:
|
||||||
@go mod tidy
|
|
||||||
@go build -buildmode=plugin -v $(DIR)...
|
@go build -buildmode=plugin -v $(DIR)...
|
||||||
|
|
||||||
|
update-deps:
|
||||||
|
@go mod tidy
|
||||||
|
@go get -u
|
||||||
|
|
||||||
format:
|
format:
|
||||||
@go fmt $(PKGS)
|
@go fmt $(PKGS)
|
||||||
|
|
14
plugins/dns_mock/go.mod
Normal file
14
plugins/dns_mock/go.mod
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
module github.com/baez90/inetmock/plugins/dns_mock
|
||||||
|
|
||||||
|
go 1.14
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/baez90/inetmock v0.0.1
|
||||||
|
github.com/miekg/dns v1.1.29
|
||||||
|
github.com/spf13/viper v1.6.3
|
||||||
|
go.uber.org/zap v1.15.0
|
||||||
|
golang.org/x/crypto v0.0.0-20200406173513-056763e48d71 // indirect
|
||||||
|
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e // indirect
|
||||||
|
)
|
||||||
|
|
||||||
|
replace github.com/baez90/inetmock v0.0.1 => ../../
|
|
@ -21,7 +21,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
|
@ -35,6 +34,7 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
@ -72,7 +72,6 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
|
||||||
github.com/miekg/dns v1.1.29 h1:xHBEhR+t5RzcFJjBLJlax2daXOrTYtr9z4WdKEfWFzg=
|
github.com/miekg/dns v1.1.29 h1:xHBEhR+t5RzcFJjBLJlax2daXOrTYtr9z4WdKEfWFzg=
|
||||||
github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4=
|
github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4=
|
||||||
github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
|
@ -81,7 +80,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI=
|
github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI=
|
||||||
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
||||||
|
@ -110,23 +108,17 @@ github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIK
|
||||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
||||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
||||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs=
|
|
||||||
github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
|
||||||
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
|
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
|
||||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||||
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
|
||||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
@ -157,11 +149,14 @@ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9E
|
||||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo=
|
go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo=
|
||||||
go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
||||||
|
go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM=
|
||||||
|
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/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-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
|
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200406173513-056763e48d71 h1:DOmugCavvUtnUD114C1Wh+UgTgQZ4pMLzXxi1pSt+/Y=
|
||||||
|
golang.org/x/crypto v0.0.0-20200406173513-056763e48d71/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
||||||
|
@ -175,8 +170,9 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/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/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g=
|
|
||||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
|
||||||
|
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/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-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-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
@ -189,12 +185,14 @@ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe h1:6fAMxZRR6sl1Uq8U61gxU+kPTs2tR8uOySCbBP7BN/M=
|
|
||||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU=
|
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU=
|
||||||
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8=
|
||||||
|
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
@ -204,6 +202,7 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
@ -220,7 +219,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
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/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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
|
|
||||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ=
|
gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ=
|
||||||
gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
@ -228,10 +226,11 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
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.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
|
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||||
|
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
|
@ -2,18 +2,18 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/baez90/inetmock/internal/config"
|
"github.com/baez90/inetmock/pkg/api"
|
||||||
|
"github.com/baez90/inetmock/pkg/logging"
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"sync"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type dnsHandler struct {
|
type dnsHandler struct {
|
||||||
logger *zap.Logger
|
logger logging.Logger
|
||||||
dnsServer []*dns.Server
|
dnsServer []*dns.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dnsHandler) Run(config config.HandlerConfig) {
|
func (d *dnsHandler) Start(config api.HandlerConfig) (err error) {
|
||||||
options := loadFromConfig(config.Options())
|
options := loadFromConfig(config.Options())
|
||||||
addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port())
|
addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port())
|
||||||
|
|
||||||
|
@ -51,6 +51,7 @@ func (d *dnsHandler) Run(config config.HandlerConfig) {
|
||||||
for _, dnsServer := range d.dnsServer {
|
for _, dnsServer := range d.dnsServer {
|
||||||
go d.startServer(dnsServer)
|
go d.startServer(dnsServer)
|
||||||
}
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dnsHandler) startServer(dnsServer *dns.Server) {
|
func (d *dnsHandler) startServer(dnsServer *dns.Server) {
|
||||||
|
@ -62,7 +63,8 @@ func (d *dnsHandler) startServer(dnsServer *dns.Server) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dnsHandler) Shutdown(wg *sync.WaitGroup) {
|
func (d *dnsHandler) Shutdown() error {
|
||||||
|
d.logger.Info("shutting down DNS mock")
|
||||||
for _, dnsServer := range d.dnsServer {
|
for _, dnsServer := range d.dnsServer {
|
||||||
if err := dnsServer.Shutdown(); err != nil {
|
if err := dnsServer.Shutdown(); err != nil {
|
||||||
d.logger.Error(
|
d.logger.Error(
|
||||||
|
@ -71,5 +73,5 @@ func (d *dnsHandler) Shutdown(wg *sync.WaitGroup) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wg.Done()
|
return nil
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/baez90/inetmock/pkg/logging"
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
@ -8,7 +9,7 @@ import (
|
||||||
type regexHandler struct {
|
type regexHandler struct {
|
||||||
routes []resolverRule
|
routes []resolverRule
|
||||||
fallback ResolverFallback
|
fallback ResolverFallback
|
||||||
logger *zap.Logger
|
logger logging.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r2 *regexHandler) AddRule(rule resolverRule) {
|
func (r2 *regexHandler) AddRule(rule resolverRule) {
|
3
plugins/go.mod
Normal file
3
plugins/go.mod
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
module github.com/baez90/inetmock/plugins
|
||||||
|
|
||||||
|
go 1.14
|
|
@ -7,17 +7,20 @@ GO_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s"
|
||||||
GO_CONTAINER_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s" -a -installsuffix cgo
|
GO_CONTAINER_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s" -a -installsuffix cgo
|
||||||
GO_DEBUG_BUILD_ARGS = -buildmode=plugin -gcflags "all=-N -l"
|
GO_DEBUG_BUILD_ARGS = -buildmode=plugin -gcflags "all=-N -l"
|
||||||
PLUGIN_NAME = $(shell basename $(DIR)).so
|
PLUGIN_NAME = $(shell basename $(DIR)).so
|
||||||
OUT_DIR = $(DIR)../../../plugins
|
OUT_DIR = $(DIR)../../
|
||||||
DEBUG_PORT = 2345
|
DEBUG_PORT = 2345
|
||||||
|
|
||||||
.PHONY: deps format compile test cli-cover-report html-cover-report
|
.PHONY: deps update-deps format compile test cli-cover-report html-cover-report
|
||||||
|
|
||||||
all: format compile test
|
all: format compile test
|
||||||
|
|
||||||
deps:
|
deps:
|
||||||
@go mod tidy
|
|
||||||
@go build -buildmode=plugin -v $(DIR)...
|
@go build -buildmode=plugin -v $(DIR)...
|
||||||
|
|
||||||
|
update-deps:
|
||||||
|
@go mod tidy
|
||||||
|
@go get -u
|
||||||
|
|
||||||
format:
|
format:
|
||||||
@go fmt $(PKGS)
|
@go fmt $(PKGS)
|
||||||
|
|
||||||
|
@ -29,7 +32,7 @@ ifdef DEBUG
|
||||||
else ifdef CONTAINER
|
else ifdef CONTAINER
|
||||||
@$(GOARGS) go build $(GO_CONTAINER_BUILD_ARGS) -o $(OUT_DIR)/$(PLUGIN_NAME) $(DIR)
|
@$(GOARGS) go build $(GO_CONTAINER_BUILD_ARGS) -o $(OUT_DIR)/$(PLUGIN_NAME) $(DIR)
|
||||||
else
|
else
|
||||||
@$(GOARGS) go build $(GO_BUILD_ARGS) -o $(OUT_DIR)/$(PLUGIN_NAMEs) $(DIR)
|
@$(GOARGS) go build $(GO_BUILD_ARGS) -o $(OUT_DIR)/$(PLUGIN_NAME) $(DIR)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
test:
|
test:
|
11
plugins/http_mock/go.mod
Normal file
11
plugins/http_mock/go.mod
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
module github.com/baez90/inetmock/plugins/http_mock
|
||||||
|
|
||||||
|
go 1.14
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/baez90/inetmock v0.0.1
|
||||||
|
github.com/spf13/viper v1.6.3
|
||||||
|
go.uber.org/zap v1.15.0
|
||||||
|
)
|
||||||
|
|
||||||
|
replace github.com/baez90/inetmock v0.0.1 => ../../
|
|
@ -21,7 +21,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
|
@ -35,6 +34,7 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
@ -70,7 +70,6 @@ github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzR
|
||||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4=
|
github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4=
|
||||||
github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
|
@ -79,7 +78,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI=
|
github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI=
|
||||||
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
||||||
|
@ -108,22 +106,17 @@ github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIK
|
||||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
||||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
||||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
|
||||||
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
|
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
|
||||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||||
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
|
||||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
@ -154,6 +147,8 @@ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9E
|
||||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo=
|
go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo=
|
||||||
go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
||||||
|
go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM=
|
||||||
|
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/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-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
@ -181,14 +176,13 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe h1:6fAMxZRR6sl1Uq8U61gxU+kPTs2tR8uOySCbBP7BN/M=
|
|
||||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU=
|
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU=
|
||||||
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8=
|
||||||
|
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
@ -198,6 +192,7 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
@ -214,7 +209,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
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/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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
|
|
||||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ=
|
gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ=
|
||||||
gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
@ -222,10 +216,11 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
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.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
|
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||||
|
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
38
plugins/http_mock/http_handler.go
Normal file
38
plugins/http_mock/http_handler.go
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"github.com/baez90/inetmock/pkg/logging"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *httpHandler) setupRoute(rule targetRule) {
|
||||||
|
p.logger.Info(
|
||||||
|
"setup routing",
|
||||||
|
zap.String("route", rule.Pattern().String()),
|
||||||
|
zap.String("response", rule.Response()),
|
||||||
|
)
|
||||||
|
|
||||||
|
p.router.Handler(rule.Pattern(), createHandlerForTarget(p.logger, rule.response))
|
||||||
|
}
|
||||||
|
|
||||||
|
func createHandlerForTarget(logger logging.Logger, targetPath string) http.Handler {
|
||||||
|
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
headerWriter := &bytes.Buffer{}
|
||||||
|
request.Header.Write(headerWriter)
|
||||||
|
|
||||||
|
logger.Info(
|
||||||
|
"Handling request",
|
||||||
|
zap.String("source", request.RemoteAddr),
|
||||||
|
zap.String("host", request.Host),
|
||||||
|
zap.String("method", request.Method),
|
||||||
|
zap.String("protocol", request.Proto),
|
||||||
|
zap.String("path", request.RequestURI),
|
||||||
|
zap.String("response", targetPath),
|
||||||
|
zap.Reflect("headers", request.Header),
|
||||||
|
)
|
||||||
|
|
||||||
|
http.ServeFile(writer, request, targetPath)
|
||||||
|
})
|
||||||
|
}
|
59
plugins/http_mock/main.go
Normal file
59
plugins/http_mock/main.go
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/baez90/inetmock/pkg/api"
|
||||||
|
"github.com/baez90/inetmock/pkg/logging"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
name = "http_mock"
|
||||||
|
)
|
||||||
|
|
||||||
|
type httpHandler struct {
|
||||||
|
logger logging.Logger
|
||||||
|
router *RegexpHandler
|
||||||
|
server *http.Server
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *httpHandler) Start(config api.HandlerConfig) (err error) {
|
||||||
|
options := loadFromConfig(config.Options())
|
||||||
|
addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port())
|
||||||
|
p.server = &http.Server{Addr: addr, Handler: p.router}
|
||||||
|
p.logger = p.logger.With(
|
||||||
|
zap.String("address", addr),
|
||||||
|
)
|
||||||
|
|
||||||
|
for _, rule := range options.Rules {
|
||||||
|
p.setupRoute(rule)
|
||||||
|
}
|
||||||
|
|
||||||
|
go p.startServer()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *httpHandler) Shutdown() (err error) {
|
||||||
|
p.logger.Info("Shutting down HTTP mock")
|
||||||
|
if err = p.server.Close(); err != nil {
|
||||||
|
p.logger.Error(
|
||||||
|
"failed to shutdown HTTP server",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
err = fmt.Errorf(
|
||||||
|
"failed to shutdown HTTP server: %w",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *httpHandler) startServer() {
|
||||||
|
if err := p.server.ListenAndServe(); err != nil {
|
||||||
|
p.logger.Error(
|
||||||
|
"failed to start http listener",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,8 +28,7 @@ type httpOptions struct {
|
||||||
Rules []targetRule
|
Rules []targetRule
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadFromConfig(config *viper.Viper) httpOptions {
|
func loadFromConfig(config *viper.Viper) (options httpOptions) {
|
||||||
options := httpOptions{}
|
|
||||||
anonRules := config.Get(rulesConfigKey).([]interface{})
|
anonRules := config.Get(rulesConfigKey).([]interface{})
|
||||||
|
|
||||||
for _, i := range anonRules {
|
for _, i := range anonRules {
|
||||||
|
@ -45,5 +44,5 @@ func loadFromConfig(config *viper.Viper) httpOptions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return options
|
return
|
||||||
}
|
}
|
|
@ -7,17 +7,20 @@ GO_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s"
|
||||||
GO_CONTAINER_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s" -a -installsuffix cgo
|
GO_CONTAINER_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s" -a -installsuffix cgo
|
||||||
GO_DEBUG_BUILD_ARGS = -buildmode=plugin -gcflags "all=-N -l"
|
GO_DEBUG_BUILD_ARGS = -buildmode=plugin -gcflags "all=-N -l"
|
||||||
PLUGIN_NAME = $(shell basename $(DIR)).so
|
PLUGIN_NAME = $(shell basename $(DIR)).so
|
||||||
OUT_DIR = $(DIR)../../../plugins
|
OUT_DIR = $(DIR)../../
|
||||||
DEBUG_PORT = 2345
|
DEBUG_PORT = 2345
|
||||||
|
|
||||||
.PHONY: deps format compile test cli-cover-report html-cover-report
|
.PHONY: deps update-deps format compile test cli-cover-report html-cover-report
|
||||||
|
|
||||||
all: format compile test
|
all: format compile test
|
||||||
|
|
||||||
deps:
|
deps:
|
||||||
@go mod tidy
|
|
||||||
@go build -buildmode=plugin -v $(DIR)...
|
@go build -buildmode=plugin -v $(DIR)...
|
||||||
|
|
||||||
|
update-deps:
|
||||||
|
@go mod tidy
|
||||||
|
@go get -u
|
||||||
|
|
||||||
format:
|
format:
|
||||||
@go fmt $(PKGS)
|
@go fmt $(PKGS)
|
||||||
|
|
||||||
|
@ -29,7 +32,7 @@ ifdef DEBUG
|
||||||
else ifdef CONTAINER
|
else ifdef CONTAINER
|
||||||
@$(GOARGS) go build $(GO_CONTAINER_BUILD_ARGS) -o $(OUT_DIR)/$(PLUGIN_NAME) $(DIR)
|
@$(GOARGS) go build $(GO_CONTAINER_BUILD_ARGS) -o $(OUT_DIR)/$(PLUGIN_NAME) $(DIR)
|
||||||
else
|
else
|
||||||
@$(GOARGS) go build $(GO_BUILD_ARGS) -o $(OUT_DIR)/$(PLUGIN_NAMEs) $(DIR)
|
@$(GOARGS) go build $(GO_BUILD_ARGS) -o $(OUT_DIR)/$(PLUGIN_NAME) $(DIR)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
test:
|
test:
|
12
plugins/http_proxy/go.mod
Normal file
12
plugins/http_proxy/go.mod
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
module github.com/baez90/inetmock/plugins/http_proxy
|
||||||
|
|
||||||
|
go 1.14
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/baez90/inetmock v0.0.1
|
||||||
|
github.com/spf13/viper v1.6.3
|
||||||
|
go.uber.org/zap v1.15.0
|
||||||
|
gopkg.in/elazarl/goproxy.v1 v1.0.0-20180725130230-947c36da3153
|
||||||
|
)
|
||||||
|
|
||||||
|
replace github.com/baez90/inetmock v0.0.1 => ../../
|
233
plugins/http_proxy/go.sum
Normal file
233
plugins/http_proxy/go.sum
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||||
|
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
|
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
|
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
|
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||||
|
github.com/elazarl/goproxy v0.0.0-20200315184450-1f3cb6622dad h1:zPs0fNF2Io1Qytf92EI2CDJ9oCXZr+NmjEVexrUEdq4=
|
||||||
|
github.com/elazarl/goproxy v0.0.0-20200315184450-1f3cb6622dad/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||||
|
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 h1:dWB6v3RcOy03t/bUadywsbyrQwCqZeNIEX6M1OtSZOM=
|
||||||
|
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
|
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||||
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
|
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/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
|
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||||
|
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
|
github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4=
|
||||||
|
github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
|
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/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
|
github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI=
|
||||||
|
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
||||||
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
|
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||||
|
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
|
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||||
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
|
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
|
||||||
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
|
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||||
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
|
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
|
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
||||||
|
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||||
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
|
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
||||||
|
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
|
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
|
||||||
|
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||||
|
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||||
|
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||||
|
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||||
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||||
|
github.com/spf13/viper v1.6.3 h1:pDDu1OyEDTKzpJwdq4TiuLyMsUgRa/BT5cn5O62NoHs=
|
||||||
|
github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw=
|
||||||
|
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.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||||
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
|
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||||
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
|
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||||
|
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
|
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
|
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
|
||||||
|
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||||
|
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
|
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
|
||||||
|
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||||
|
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
|
||||||
|
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||||
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
|
go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo=
|
||||||
|
go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
||||||
|
go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM=
|
||||||
|
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
||||||
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/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-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
||||||
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||||
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/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-20181220203305-927f97764cc3/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/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU=
|
||||||
|
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8=
|
||||||
|
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425 h1:VvQyQJN0tSuecqgcIxMWnnfG5kSmgy9KZR9sW3W5QeA=
|
||||||
|
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
|
gopkg.in/check.v1 v0.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/elazarl/goproxy.v1 v1.0.0-20180725130230-947c36da3153 h1:i2sumy6EgvN2dbX7HPhoDc7hLyoym3OYdU5HlvUUrpE=
|
||||||
|
gopkg.in/elazarl/goproxy.v1 v1.0.0-20180725130230-947c36da3153/go.mod h1:xzjpkyedLMz3EXUTBbkRuuGPsxfsBX3Sy7J6kC9Gvoc=
|
||||||
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
|
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ=
|
||||||
|
gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
|
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.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||||
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
|
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||||
|
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
23
plugins/http_proxy/init.go
Normal file
23
plugins/http_proxy/init.go
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/baez90/inetmock/internal/plugins"
|
||||||
|
"github.com/baez90/inetmock/pkg/api"
|
||||||
|
"github.com/baez90/inetmock/pkg/logging"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"gopkg.in/elazarl/goproxy.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
logger, _ := logging.CreateLogger()
|
||||||
|
logger = logger.With(
|
||||||
|
zap.String("ProtocolHandler", name),
|
||||||
|
)
|
||||||
|
|
||||||
|
plugins.Registry().RegisterHandler(name, func() api.ProtocolHandler {
|
||||||
|
return &httpProxy{
|
||||||
|
logger: logger,
|
||||||
|
proxy: goproxy.NewProxyHttpServer(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
71
plugins/http_proxy/main.go
Normal file
71
plugins/http_proxy/main.go
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/baez90/inetmock/pkg/api"
|
||||||
|
"github.com/baez90/inetmock/pkg/logging"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"gopkg.in/elazarl/goproxy.v1"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
name = "http_proxy"
|
||||||
|
)
|
||||||
|
|
||||||
|
type httpProxy struct {
|
||||||
|
logger logging.Logger
|
||||||
|
proxy *goproxy.ProxyHttpServer
|
||||||
|
server *http.Server
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *httpProxy) Start(config api.HandlerConfig) (err error) {
|
||||||
|
options := loadFromConfig(config.Options())
|
||||||
|
addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port())
|
||||||
|
h.server = &http.Server{Addr: addr, Handler: h.proxy}
|
||||||
|
h.logger = h.logger.With(
|
||||||
|
zap.String("address", addr),
|
||||||
|
)
|
||||||
|
|
||||||
|
tlsConfig := api.ServicesInstance().CertStore().TLSConfig()
|
||||||
|
|
||||||
|
proxyHandler := &proxyHttpHandler{
|
||||||
|
options: options,
|
||||||
|
logger: h.logger,
|
||||||
|
}
|
||||||
|
|
||||||
|
proxyHttpsHandler := &proxyHttpsHandler{
|
||||||
|
tlsConfig: tlsConfig,
|
||||||
|
logger: h.logger,
|
||||||
|
}
|
||||||
|
|
||||||
|
h.proxy.OnRequest().Do(proxyHandler)
|
||||||
|
h.proxy.OnRequest().HandleConnect(proxyHttpsHandler)
|
||||||
|
go h.startProxy()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *httpProxy) startProxy() {
|
||||||
|
if err := h.server.ListenAndServe(); err != nil {
|
||||||
|
h.logger.Error(
|
||||||
|
"failed to start proxy server",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *httpProxy) Shutdown() (err error) {
|
||||||
|
h.logger.Info("Shutting down HTTP proxy")
|
||||||
|
if err = h.server.Close(); err != nil {
|
||||||
|
h.logger.Error(
|
||||||
|
"failed to shutdown proxy endpoint",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
|
||||||
|
err = fmt.Errorf(
|
||||||
|
"failed to shutdown proxy endpoint: %w",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
42
plugins/http_proxy/protocol_options.go
Normal file
42
plugins/http_proxy/protocol_options.go
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
targetSchemeConfigKey = "target.scheme"
|
||||||
|
targetIpAddressConfigKey = "target.ipAddress"
|
||||||
|
targetPortConfigKey = "target.port"
|
||||||
|
)
|
||||||
|
|
||||||
|
type redirectionTarget struct {
|
||||||
|
scheme string
|
||||||
|
ipAddress string
|
||||||
|
port uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rt redirectionTarget) host() string {
|
||||||
|
return fmt.Sprintf("%s:%d", rt.ipAddress, rt.port)
|
||||||
|
}
|
||||||
|
|
||||||
|
type httpProxyOptions struct {
|
||||||
|
redirectionTarget redirectionTarget
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadFromConfig(config *viper.Viper) (options httpProxyOptions) {
|
||||||
|
|
||||||
|
config.SetDefault(targetSchemeConfigKey, "http")
|
||||||
|
config.SetDefault(targetIpAddressConfigKey, "127.0.0.1")
|
||||||
|
config.SetDefault(targetPortConfigKey, "80")
|
||||||
|
|
||||||
|
options = httpProxyOptions{
|
||||||
|
redirectionTarget{
|
||||||
|
scheme: config.GetString(targetSchemeConfigKey),
|
||||||
|
ipAddress: config.GetString(targetIpAddressConfigKey),
|
||||||
|
port: uint16(config.GetInt(targetPortConfigKey)),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
1
plugins/http_proxy/protocol_options_test.go
Normal file
1
plugins/http_proxy/protocol_options_test.go
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package main
|
93
plugins/http_proxy/proxy_handler.go
Normal file
93
plugins/http_proxy/proxy_handler.go
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"github.com/baez90/inetmock/pkg/logging"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"gopkg.in/elazarl/goproxy.v1"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
type proxyHttpHandler struct {
|
||||||
|
options httpProxyOptions
|
||||||
|
logger logging.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
type proxyHttpsHandler struct {
|
||||||
|
tlsConfig *tls.Config
|
||||||
|
logger logging.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *proxyHttpsHandler) HandleConnect(req string, _ *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) {
|
||||||
|
p.logger.Info(
|
||||||
|
"Intercepting HTTPS proxy request",
|
||||||
|
zap.String("request", req),
|
||||||
|
)
|
||||||
|
|
||||||
|
return &goproxy.ConnectAction{
|
||||||
|
Action: goproxy.ConnectMitm,
|
||||||
|
TLSConfig: func(host string, ctx *goproxy.ProxyCtx) (*tls.Config, error) {
|
||||||
|
return p.tlsConfig, nil
|
||||||
|
},
|
||||||
|
}, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *proxyHttpHandler) Handle(req *http.Request, ctx *goproxy.ProxyCtx) (retReq *http.Request, resp *http.Response) {
|
||||||
|
retReq = req
|
||||||
|
p.logger.Info(
|
||||||
|
"Handling request",
|
||||||
|
zap.String("source", req.RemoteAddr),
|
||||||
|
zap.String("host", req.Host),
|
||||||
|
zap.String("method", req.Method),
|
||||||
|
zap.String("protocol", req.Proto),
|
||||||
|
zap.String("path", req.RequestURI),
|
||||||
|
zap.Reflect("headers", req.Header),
|
||||||
|
)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
if resp, err = ctx.RoundTrip(p.redirectHTTPRequest(req)); err != nil {
|
||||||
|
p.logger.Error(
|
||||||
|
"error while doing roundtrip",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return req, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p proxyHttpHandler) redirectHTTPRequest(originalRequest *http.Request) (redirectReq *http.Request) {
|
||||||
|
redirectReq = &http.Request{
|
||||||
|
Method: originalRequest.Method,
|
||||||
|
URL: &url.URL{
|
||||||
|
Host: p.options.redirectionTarget.host(),
|
||||||
|
Scheme: p.options.redirectionTarget.scheme,
|
||||||
|
Path: originalRequest.URL.Path,
|
||||||
|
ForceQuery: originalRequest.URL.ForceQuery,
|
||||||
|
Fragment: originalRequest.URL.Fragment,
|
||||||
|
Opaque: originalRequest.URL.Opaque,
|
||||||
|
RawPath: originalRequest.URL.RawPath,
|
||||||
|
RawQuery: originalRequest.URL.RawQuery,
|
||||||
|
User: originalRequest.URL.User,
|
||||||
|
},
|
||||||
|
Proto: originalRequest.Proto,
|
||||||
|
ProtoMajor: originalRequest.ProtoMajor,
|
||||||
|
ProtoMinor: originalRequest.ProtoMinor,
|
||||||
|
Header: originalRequest.Header,
|
||||||
|
Body: originalRequest.Body,
|
||||||
|
GetBody: originalRequest.GetBody,
|
||||||
|
ContentLength: originalRequest.ContentLength,
|
||||||
|
TransferEncoding: originalRequest.TransferEncoding,
|
||||||
|
Close: false,
|
||||||
|
Host: originalRequest.Host,
|
||||||
|
Form: originalRequest.Form,
|
||||||
|
PostForm: originalRequest.PostForm,
|
||||||
|
MultipartForm: originalRequest.MultipartForm,
|
||||||
|
Trailer: originalRequest.Trailer,
|
||||||
|
}
|
||||||
|
redirectReq = redirectReq.WithContext(context.Background())
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
47
plugins/tls_interceptor/Makefile
Normal file
47
plugins/tls_interceptor/Makefile
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
VERSION = $(shell git describe --dirty --tags --always)
|
||||||
|
DIR = $(dir $(realpath $(firstword $(MAKEFILE_LIST))))
|
||||||
|
PKGS = $(shell go list ./...)
|
||||||
|
TEST_PKGS = $(shell find . -type f -name "*_test.go" -printf '%h\n' | sort -u)
|
||||||
|
GOARGS = GOOS=linux GOARCH=amd64
|
||||||
|
GO_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s"
|
||||||
|
GO_CONTAINER_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s" -a -installsuffix cgo
|
||||||
|
GO_DEBUG_BUILD_ARGS = -buildmode=plugin -gcflags "all=-N -l"
|
||||||
|
PLUGIN_NAME = $(shell basename $(DIR)).so
|
||||||
|
OUT_DIR = $(DIR)../../
|
||||||
|
DEBUG_PORT = 2345
|
||||||
|
|
||||||
|
.PHONY: deps update-deps format compile test cli-cover-report html-cover-report
|
||||||
|
|
||||||
|
all: format compile test
|
||||||
|
|
||||||
|
deps:
|
||||||
|
@go build -buildmode=plugin -v $(DIR)...
|
||||||
|
|
||||||
|
update-deps:
|
||||||
|
@go mod tidy
|
||||||
|
@go get -u
|
||||||
|
|
||||||
|
format:
|
||||||
|
@go fmt $(PKGS)
|
||||||
|
|
||||||
|
compile: deps
|
||||||
|
@mkdir -p $(OUT_DIR)
|
||||||
|
ifdef DEBUG
|
||||||
|
@echo 'Compiling for debugging...'
|
||||||
|
@$(GOARGS) go build $(GO_DEBUG_BUILD_ARGS) -o $(OUT_DIR)/$(PLUGIN_NAME) $(DIR)
|
||||||
|
else ifdef CONTAINER
|
||||||
|
@$(GOARGS) go build $(GO_CONTAINER_BUILD_ARGS) -o $(OUT_DIR)/$(PLUGIN_NAME) $(DIR)
|
||||||
|
else
|
||||||
|
@$(GOARGS) go build $(GO_BUILD_ARGS) -o $(OUT_DIR)/$(PLUGIN_NAME) $(DIR)
|
||||||
|
endif
|
||||||
|
|
||||||
|
test:
|
||||||
|
@go test -coverprofile=./cov-raw.out -v $(TEST_PKGS)
|
||||||
|
@cat ./cov-raw.out | grep -v "generated" > ./cov.out
|
||||||
|
@rm -f $(DIR)$(PLUGIN_NAME)
|
||||||
|
|
||||||
|
cli-cover-report:
|
||||||
|
@go tool cover -func=cov.out
|
||||||
|
|
||||||
|
html-cover-report:
|
||||||
|
@go tool cover -html=cov.out -o .coverage.html
|
12
plugins/tls_interceptor/go.mod
Normal file
12
plugins/tls_interceptor/go.mod
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
module github.com/baez90/inetmock/plugins/tls_interceptor
|
||||||
|
|
||||||
|
go 1.14
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/baez90/inetmock v0.0.1
|
||||||
|
github.com/google/uuid v1.1.1
|
||||||
|
github.com/spf13/viper v1.6.3
|
||||||
|
go.uber.org/zap v1.15.0
|
||||||
|
)
|
||||||
|
|
||||||
|
replace github.com/baez90/inetmock v0.0.1 => ../../
|
|
@ -21,7 +21,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
|
@ -35,12 +34,15 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
|
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||||
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
|
@ -70,7 +72,6 @@ github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzR
|
||||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4=
|
github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4=
|
||||||
github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
|
@ -79,7 +80,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI=
|
github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI=
|
||||||
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
||||||
|
@ -108,23 +108,17 @@ github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIK
|
||||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
||||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
||||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs=
|
|
||||||
github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
|
||||||
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
|
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
|
||||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||||
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
|
||||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
@ -155,6 +149,8 @@ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9E
|
||||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo=
|
go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo=
|
||||||
go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
||||||
|
go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM=
|
||||||
|
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/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-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
@ -182,14 +178,13 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe h1:6fAMxZRR6sl1Uq8U61gxU+kPTs2tR8uOySCbBP7BN/M=
|
|
||||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU=
|
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU=
|
||||||
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8=
|
||||||
|
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
@ -199,6 +194,7 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
@ -215,7 +211,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
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/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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
|
|
||||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ=
|
gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ=
|
||||||
gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
@ -223,10 +218,11 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
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.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
|
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||||
|
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"github.com/baez90/inetmock/internal/plugins"
|
"github.com/baez90/inetmock/internal/plugins"
|
||||||
"github.com/baez90/inetmock/pkg/api"
|
"github.com/baez90/inetmock/pkg/api"
|
||||||
"github.com/baez90/inetmock/pkg/logging"
|
"github.com/baez90/inetmock/pkg/logging"
|
||||||
|
"github.com/google/uuid"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
@ -18,6 +19,7 @@ func init() {
|
||||||
return &tlsInterceptor{
|
return &tlsInterceptor{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
currentConnectionsCount: &sync.WaitGroup{},
|
currentConnectionsCount: &sync.WaitGroup{},
|
||||||
|
currentConnections: make(map[uuid.UUID]*proxyConn),
|
||||||
}
|
}
|
||||||
}, generateCACmd(logger))
|
})
|
||||||
}
|
}
|
|
@ -2,9 +2,11 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/baez90/inetmock/internal/config"
|
"github.com/baez90/inetmock/pkg/api"
|
||||||
|
"github.com/baez90/inetmock/pkg/cert"
|
||||||
|
"github.com/baez90/inetmock/pkg/logging"
|
||||||
|
"github.com/google/uuid"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -16,17 +18,16 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type tlsInterceptor struct {
|
type tlsInterceptor struct {
|
||||||
logger *zap.Logger
|
options tlsOptions
|
||||||
|
logger logging.Logger
|
||||||
listener net.Listener
|
listener net.Listener
|
||||||
certStore *certStore
|
certStore cert.Store
|
||||||
options *tlsOptions
|
|
||||||
shutdownRequested bool
|
shutdownRequested bool
|
||||||
currentConnectionsCount *sync.WaitGroup
|
currentConnectionsCount *sync.WaitGroup
|
||||||
currentConnections []*proxyConn
|
currentConnections map[uuid.UUID]*proxyConn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tlsInterceptor) Run(config config.HandlerConfig) {
|
func (t *tlsInterceptor) Start(config api.HandlerConfig) (err error) {
|
||||||
var err error
|
|
||||||
t.options = loadFromConfig(config.Options())
|
t.options = loadFromConfig(config.Options())
|
||||||
addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port())
|
addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port())
|
||||||
|
|
||||||
|
@ -35,39 +36,24 @@ func (t *tlsInterceptor) Run(config config.HandlerConfig) {
|
||||||
zap.String("target", t.options.redirectionTarget.address()),
|
zap.String("target", t.options.redirectionTarget.address()),
|
||||||
)
|
)
|
||||||
|
|
||||||
t.certStore = &certStore{
|
if t.listener, err = tls.Listen("tcp", addr, api.ServicesInstance().CertStore().TLSConfig()); err != nil {
|
||||||
options: t.options,
|
|
||||||
certCache: make(map[string]*tls.Certificate),
|
|
||||||
logger: t.logger,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = t.certStore.initCaCert(); err != nil {
|
|
||||||
t.logger.Error(
|
|
||||||
"failed to initialize CA cert",
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
rootCaPool := x509.NewCertPool()
|
|
||||||
rootCaPool.AddCert(t.certStore.caCert)
|
|
||||||
|
|
||||||
tlsConfig := &tls.Config{
|
|
||||||
GetCertificate: t.getCert,
|
|
||||||
RootCAs: rootCaPool,
|
|
||||||
}
|
|
||||||
|
|
||||||
if t.listener, err = tls.Listen("tcp", addr, tlsConfig); err != nil {
|
|
||||||
t.logger.Fatal(
|
t.logger.Fatal(
|
||||||
"failed to create tls listener",
|
"failed to create tls listener",
|
||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
)
|
)
|
||||||
|
err = fmt.Errorf(
|
||||||
|
"failed to create tls listener: %w",
|
||||||
|
err,
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
go t.startListener()
|
go t.startListener()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tlsInterceptor) Shutdown(wg *sync.WaitGroup) {
|
func (t *tlsInterceptor) Shutdown() (err error) {
|
||||||
|
t.logger.Info("Shutting down TLS interceptor")
|
||||||
t.shutdownRequested = true
|
t.shutdownRequested = true
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -77,17 +63,21 @@ func (t *tlsInterceptor) Shutdown(wg *sync.WaitGroup) {
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-done:
|
case <-done:
|
||||||
wg.Done()
|
return
|
||||||
case <-time.After(5 * time.Second):
|
case <-time.After(5 * time.Second):
|
||||||
for _, proxyConn := range t.currentConnections {
|
for _, proxyConn := range t.currentConnections {
|
||||||
if err := proxyConn.Close(); err != nil {
|
if err = proxyConn.Close(); err != nil {
|
||||||
t.logger.Error(
|
t.logger.Error(
|
||||||
"error while closing remaining proxy connections",
|
"error while closing remaining proxy connections",
|
||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
)
|
)
|
||||||
|
err = fmt.Errorf(
|
||||||
|
"error while closing remaining proxy connections: %w",
|
||||||
|
err,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wg.Done()
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,25 +97,9 @@ func (t *tlsInterceptor) startListener() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tlsInterceptor) getCert(info *tls.ClientHelloInfo) (cert *tls.Certificate, err error) {
|
|
||||||
var localIp string
|
|
||||||
if localIp, err = extractIPFromAddress(info.Conn.LocalAddr().String()); err != nil {
|
|
||||||
localIp = "127.0.0.1"
|
|
||||||
}
|
|
||||||
if cert, err = t.certStore.getCertificate(info.ServerName, localIp); err != nil {
|
|
||||||
t.logger.Error(
|
|
||||||
"error while resolving certificate",
|
|
||||||
zap.String("serverName", info.ServerName),
|
|
||||||
zap.String("localAddr", localIp),
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *tlsInterceptor) proxyConn(conn net.Conn) {
|
func (t *tlsInterceptor) proxyConn(conn net.Conn) {
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
defer t.currentConnectionsCount.Done()
|
||||||
|
|
||||||
rAddr, err := net.ResolveTCPAddr("tcp", t.options.redirectionTarget.address())
|
rAddr, err := net.ResolveTCPAddr("tcp", t.options.redirectionTarget.address())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -145,14 +119,16 @@ func (t *tlsInterceptor) proxyConn(conn net.Conn) {
|
||||||
}
|
}
|
||||||
defer targetConn.Close()
|
defer targetConn.Close()
|
||||||
|
|
||||||
t.currentConnections = append(t.currentConnections, &proxyConn{
|
proxyCon := &proxyConn{
|
||||||
source: conn,
|
source: conn,
|
||||||
target: targetConn,
|
target: targetConn,
|
||||||
})
|
}
|
||||||
|
|
||||||
|
conUID := uuid.New()
|
||||||
|
t.currentConnections[conUID] = proxyCon
|
||||||
Pipe(conn, targetConn)
|
Pipe(conn, targetConn)
|
||||||
|
delete(t.currentConnections, conUID)
|
||||||
|
|
||||||
t.currentConnectionsCount.Done()
|
|
||||||
t.logger.Info(
|
t.logger.Info(
|
||||||
"connection closed",
|
"connection closed",
|
||||||
zap.String("remoteAddr", conn.RemoteAddr().String()),
|
zap.String("remoteAddr", conn.RemoteAddr().String()),
|
33
plugins/tls_interceptor/protocol_options.go
Normal file
33
plugins/tls_interceptor/protocol_options.go
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
targetIpAddressConfigKey = "target.ipAddress"
|
||||||
|
targetPortConfigKey = "target.port"
|
||||||
|
)
|
||||||
|
|
||||||
|
type redirectionTarget struct {
|
||||||
|
ipAddress string
|
||||||
|
port uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rt redirectionTarget) address() string {
|
||||||
|
return fmt.Sprintf("%s:%d", rt.ipAddress, rt.port)
|
||||||
|
}
|
||||||
|
|
||||||
|
type tlsOptions struct {
|
||||||
|
redirectionTarget redirectionTarget
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadFromConfig(config *viper.Viper) tlsOptions {
|
||||||
|
return tlsOptions{
|
||||||
|
redirectionTarget: redirectionTarget{
|
||||||
|
ipAddress: config.GetString(targetIpAddressConfigKey),
|
||||||
|
port: uint16(config.GetInt(targetPortConfigKey)),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
77
proxy_config.yaml
Normal file
77
proxy_config.yaml
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
endpoints:
|
||||||
|
plainHttp:
|
||||||
|
handler: http_proxy
|
||||||
|
listenAddress: 0.0.0.0
|
||||||
|
port: 80
|
||||||
|
options:
|
||||||
|
rules:
|
||||||
|
- pattern: ".*\\.(?i)exe"
|
||||||
|
response: ./assets/fakeFiles/sample.exe
|
||||||
|
- pattern: ".*\\.(?i)(jpg|jpeg)"
|
||||||
|
response: ./assets/fakeFiles/default.jpg
|
||||||
|
- pattern: ".*\\.(?i)png"
|
||||||
|
response: ./assets/fakeFiles/default.png
|
||||||
|
- pattern: ".*\\.(?i)gif"
|
||||||
|
response: ./assets/fakeFiles/default.gif
|
||||||
|
- pattern: ".*\\.(?i)ico"
|
||||||
|
response: ./assets/fakeFiles/default.ico
|
||||||
|
- pattern: ".*\\.(?i)txt"
|
||||||
|
response: ./assets/fakeFiles/default.txt
|
||||||
|
- pattern: ".*"
|
||||||
|
response: ./assets/fakeFiles/default.html
|
||||||
|
httpsDowngrade:
|
||||||
|
handler: tls_interceptor
|
||||||
|
listenAddress: 0.0.0.0
|
||||||
|
port: 443
|
||||||
|
options:
|
||||||
|
ecdsaCurve: P256
|
||||||
|
validity:
|
||||||
|
ca:
|
||||||
|
notBeforeRelative: 17520h
|
||||||
|
notAfterRelative: 17520h
|
||||||
|
domain:
|
||||||
|
notBeforeRelative: 168h
|
||||||
|
notAfterRelative: 168h
|
||||||
|
rootCaCert:
|
||||||
|
publicKey: ./ca.pem
|
||||||
|
privateKey: ./ca.key
|
||||||
|
certCachePath: /tmp/inetmock/
|
||||||
|
target:
|
||||||
|
ipAddress: 127.0.0.1
|
||||||
|
port: 80
|
||||||
|
plainDns:
|
||||||
|
handler: dns_mock
|
||||||
|
listenAddress: 0.0.0.0
|
||||||
|
port: 53
|
||||||
|
options:
|
||||||
|
rules:
|
||||||
|
- pattern: "www.golem.de"
|
||||||
|
response: 77.247.84.129
|
||||||
|
- pattern: ".*\\.google\\.com"
|
||||||
|
response: 1.1.1.1
|
||||||
|
- pattern: ".*\\.reddit\\.com"
|
||||||
|
response: 2.2.2.2
|
||||||
|
fallback:
|
||||||
|
strategy: incremental
|
||||||
|
args:
|
||||||
|
startIP: 10.0.0.0
|
||||||
|
dnsOverTlsDowngrade:
|
||||||
|
handler: tls_interceptor
|
||||||
|
listenAddress: 0.0.0.0
|
||||||
|
port: 853
|
||||||
|
options:
|
||||||
|
ecdsaCurve: P256
|
||||||
|
validity:
|
||||||
|
ca:
|
||||||
|
notBeforeRelative: 17520h
|
||||||
|
notAfterRelative: 17520h
|
||||||
|
domain:
|
||||||
|
notBeforeRelative: 168h
|
||||||
|
notAfterRelative: 168h
|
||||||
|
rootCaCert:
|
||||||
|
publicKey: ./ca.pem
|
||||||
|
privateKey: ./ca.key
|
||||||
|
certCachePath: /tmp/inetmock/
|
||||||
|
target:
|
||||||
|
ipAddress: 127.0.0.1
|
||||||
|
port: 53
|
Loading…
Reference in a new issue