pax_global_header00006660000000000000000000000064141544107150014514gustar00rootroot0000000000000052 comment=d993ec6611e20aee06eb58f5afc4f43b90ea82c7 golang-github-prometheus-exporter-toolkit-0.7.1/000077500000000000000000000000001415441071500217725ustar00rootroot00000000000000golang-github-prometheus-exporter-toolkit-0.7.1/.circleci/000077500000000000000000000000001415441071500236255ustar00rootroot00000000000000golang-github-prometheus-exporter-toolkit-0.7.1/.circleci/config.yml000066400000000000000000000017111415441071500256150ustar00rootroot00000000000000--- version: 2.1 orbs: go: circleci/go@0.2.0 jobs: test: parameters: go_version: type: string use_gomod_cache: type: boolean default: true docker: - image: circleci/golang:<< parameters.go_version >> working_directory: /go/src/github.com/prometheus/exporter-toolkit steps: - checkout - when: condition: << parameters.use_gomod_cache >> steps: - go/load-cache: key: v1-go<< parameters.go_version >> - run: make test - when: condition: << parameters.use_gomod_cache >> steps: - go/save-cache: key: v1-go<< parameters.go_version >> - store_test_results: path: test-results workflows: version: 2 tests: jobs: # Support the last two go releases, as per https://golang.org/dl/. - test: name: go-1-14 go_version: "1.14" - test: name: go-1-15 go_version: "1.15" golang-github-prometheus-exporter-toolkit-0.7.1/.github/000077500000000000000000000000001415441071500233325ustar00rootroot00000000000000golang-github-prometheus-exporter-toolkit-0.7.1/.github/ISSUE_TEMPLATE.md000066400000000000000000000024151415441071500260410ustar00rootroot00000000000000 golang-github-prometheus-exporter-toolkit-0.7.1/.github/workflows/000077500000000000000000000000001415441071500253675ustar00rootroot00000000000000golang-github-prometheus-exporter-toolkit-0.7.1/.github/workflows/codeql-analysis.yml000066400000000000000000000045001415441071500312010ustar00rootroot00000000000000# For most projects, this workflow file will not need changing; you simply need # to commit it to your repository. # # You may wish to alter this file to override the set of languages analyzed, # or to provide custom queries or build logic. # # ******** NOTE ******** # We have attempted to detect the languages in your repository. Please check # the `language` matrix defined below to confirm you have the correct set of # supported CodeQL languages. # name: "CodeQL" on: push: branches: [ master, release-* ] pull_request: # The branches below must be a subset of the branches above branches: [ master ] schedule: - cron: '26 14 * * 1' jobs: analyze: name: Analyze runs-on: ubuntu-latest strategy: fail-fast: false matrix: language: [ 'go' ] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] # Learn more: # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed steps: - name: Checkout repository uses: actions/checkout@v2 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v1 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. # queries: ./path/to/local/query, your-org/your-repo/queries@main # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild uses: github/codeql-action/autobuild@v1 # â„šī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl # âœī¸ If the Autobuild fails above, remove it and uncomment the following three lines # and modify them (or add more) to build your code if your project # uses a compiled language #- run: | # make bootstrap # make release - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v1 golang-github-prometheus-exporter-toolkit-0.7.1/.github/workflows/golangci-lint.yml000066400000000000000000000011761415441071500306460ustar00rootroot00000000000000name: golangci-lint on: push: paths: - "go.sum" - "go.mod" - "**.go" - "scripts/errcheck_excludes.txt" - ".github/workflows/golangci-lint.yml" - ".golangci.yml" pull_request: paths: - "go.sum" - "go.mod" - "**.go" - "scripts/errcheck_excludes.txt" - ".github/workflows/golangci-lint.yml" - ".golangci.yml" jobs: golangci: name: lint runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v2 - name: Lint uses: golangci/golangci-lint-action@v2 with: version: v1.42.0 golang-github-prometheus-exporter-toolkit-0.7.1/.golangci.yml000066400000000000000000000002611415441071500243550ustar00rootroot00000000000000linters: enable: - golint issues: exclude-rules: - path: _test.go linters: - errcheck linters-settings: errcheck: exclude: scripts/errcheck_excludes.txt golang-github-prometheus-exporter-toolkit-0.7.1/CHANGELOG.md000066400000000000000000000030741415441071500236070ustar00rootroot00000000000000## 0.7.1 / 2021-12-02 * [BUGFIX] Effectively enable HTTP/2 support. #72 ## 0.7.0 / 2021-10-19 * [FEATURE] Add support for security-related HTTP headers. #41 ## 0.6.1 / 2021-06-30 * [BUGFIX] Allow RequireAnyClientCert as client_auth_type. #58 ## 0.6.0 / 2021-06-30 * [CHANGE] Move from github.com/go-kit/kit/log to github.com/go-kit/log #55 ## 0.5.1 / 2021-01-15 This release includes a bugfix for a side-channel security issue that would allow an attacker to verify if a user is defined in the configuration by timing request. #39 * [ENHANCEMENT] Cache basic authentication results to significantly improve performance. #32 * [BUGFIX] Prevent user enumeration by timing requests. #39 ## 0.5.0 / 2021-01-13 * [CHANGE] rename `https` package to `web`. #29 * [CHANGE] `web`: Rename Listen() to ListenAndServe(). #28 ## 0.4.0 / 2020-12-26 This release now correctly resolves relative paths with regards to the configuration file, instead of the current working directory. * [FEATURE] `https`: Add a Validate() function. #22 * [ENHANCEMENT] `https`: Mark kingpin flag as experimental. #20 * [BUGFIX] `https`: Make certificate paths relative to configuration file. #21 ## 0.3.0 / 2020-12-25 * [FEATURE] `https`: Add Serve to use an existing listener. #16 * [BUGFIX] Return 401 Unauthorized when a bad password is used. Previously we returned 403 Forbidden in that case. #17 ## 0.2.0 / 2020-12-16 * [FEATURE] `https/kingpinflags` package for adding kingpin support for TLS. #12 ## 0.1.0 / 2020-12-10 Initial release. * [FEATURE] `https` package for adding TLS to exporters. #8 golang-github-prometheus-exporter-toolkit-0.7.1/CODE_OF_CONDUCT.md000066400000000000000000000002331415441071500245670ustar00rootroot00000000000000## Prometheus Community Code of Conduct Prometheus follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). golang-github-prometheus-exporter-toolkit-0.7.1/CONTRIBUTING.md000066400000000000000000000016661415441071500242340ustar00rootroot00000000000000# Contributing Prometheus uses GitHub to manage reviews of pull requests. * If you have a trivial fix or improvement, go ahead and create a pull request, addressing (with `@...`) the maintainer of this repository (see [MAINTAINERS.md](MAINTAINERS.md)) in the description of the pull request. * If you plan to do something more involved, first discuss your ideas on our [mailing list](https://groups.google.com/forum/?fromgroups#!forum/prometheus-developers). This will avoid unnecessary work and surely give you and us a good deal of inspiration. * Relevant coding style guidelines are the [Go Code Review Comments](https://code.google.com/p/go-wiki/wiki/CodeReviewComments) and the _Formatting and style_ section of Peter Bourgon's [Go: Best Practices for Production Environments](http://peter.bourgon.org/go-in-production/#formatting-and-style). * Be sure to sign off on the [DCO](https://github.com/probot/dco#how-it-works) golang-github-prometheus-exporter-toolkit-0.7.1/LICENSE000066400000000000000000000261351415441071500230060ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. golang-github-prometheus-exporter-toolkit-0.7.1/MAINTAINERS.md000066400000000000000000000001441415441071500240650ustar00rootroot00000000000000* Ben Kochie @SuperQ * Julien Pivotto @roidelapluie golang-github-prometheus-exporter-toolkit-0.7.1/Makefile000066400000000000000000000013641415441071500234360ustar00rootroot00000000000000# Copyright 2020 The Prometheus Authors # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. include Makefile.common .PHONY: test test:: deps check_license unused common-test ifeq (,$(shell echo $(GO_VERSION_NUMBER) | grep -E 'go1\.(7|8|9|10)\.')) test:: lint endif golang-github-prometheus-exporter-toolkit-0.7.1/Makefile.common000066400000000000000000000244531415441071500247310ustar00rootroot00000000000000# Copyright 2018 The Prometheus Authors # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # A common Makefile that includes rules to be reused in different prometheus projects. # !!! Open PRs only against the prometheus/prometheus/Makefile.common repository! # Example usage : # Create the main Makefile in the root project directory. # include Makefile.common # customTarget: # @echo ">> Running customTarget" # # Ensure GOBIN is not set during build so that promu is installed to the correct path unexport GOBIN GO ?= go GOFMT ?= $(GO)fmt FIRST_GOPATH := $(firstword $(subst :, ,$(shell $(GO) env GOPATH))) GOOPTS ?= GOHOSTOS ?= $(shell $(GO) env GOHOSTOS) GOHOSTARCH ?= $(shell $(GO) env GOHOSTARCH) GO_VERSION ?= $(shell $(GO) version) GO_VERSION_NUMBER ?= $(word 3, $(GO_VERSION)) PRE_GO_111 ?= $(shell echo $(GO_VERSION_NUMBER) | grep -E 'go1\.(10|[0-9])\.') GOVENDOR := GO111MODULE := ifeq (, $(PRE_GO_111)) ifneq (,$(wildcard go.mod)) # Enforce Go modules support just in case the directory is inside GOPATH (and for Travis CI). GO111MODULE := on ifneq (,$(wildcard vendor)) # Always use the local vendor/ directory to satisfy the dependencies. GOOPTS := $(GOOPTS) -mod=vendor endif endif else ifneq (,$(wildcard go.mod)) ifneq (,$(wildcard vendor)) $(warning This repository requires Go >= 1.11 because of Go modules) $(warning Some recipes may not work as expected as the current Go runtime is '$(GO_VERSION_NUMBER)') endif else # This repository isn't using Go modules (yet). GOVENDOR := $(FIRST_GOPATH)/bin/govendor endif endif PROMU := $(FIRST_GOPATH)/bin/promu pkgs = ./... ifeq (arm, $(GOHOSTARCH)) GOHOSTARM ?= $(shell GOARM= $(GO) env GOARM) GO_BUILD_PLATFORM ?= $(GOHOSTOS)-$(GOHOSTARCH)v$(GOHOSTARM) else GO_BUILD_PLATFORM ?= $(GOHOSTOS)-$(GOHOSTARCH) endif GOTEST := $(GO) test GOTEST_DIR := ifneq ($(CIRCLE_JOB),) ifneq ($(shell which gotestsum),) GOTEST_DIR := test-results GOTEST := gotestsum --junitfile $(GOTEST_DIR)/unit-tests.xml -- endif endif PROMU_VERSION ?= 0.13.0 PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz GOLANGCI_LINT := GOLANGCI_LINT_OPTS ?= GOLANGCI_LINT_VERSION ?= v1.42.0 # golangci-lint only supports linux, darwin and windows platforms on i386/amd64. # windows isn't included here because of the path separator being different. ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) ifeq ($(GOHOSTARCH),$(filter $(GOHOSTARCH),amd64 i386)) # If we're in CI and there is an Actions file, that means the linter # is being run in Actions, so we don't need to run it here. ifeq (,$(CIRCLE_JOB)) GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint else ifeq (,$(wildcard .github/workflows/golangci-lint.yml)) GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint endif endif endif PREFIX ?= $(shell pwd) BIN_DIR ?= $(shell pwd) DOCKER_IMAGE_TAG ?= $(subst /,-,$(shell git rev-parse --abbrev-ref HEAD)) DOCKERFILE_PATH ?= ./Dockerfile DOCKERBUILD_CONTEXT ?= ./ DOCKER_REPO ?= prom DOCKER_ARCHS ?= amd64 BUILD_DOCKER_ARCHS = $(addprefix common-docker-,$(DOCKER_ARCHS)) PUBLISH_DOCKER_ARCHS = $(addprefix common-docker-publish-,$(DOCKER_ARCHS)) TAG_DOCKER_ARCHS = $(addprefix common-docker-tag-latest-,$(DOCKER_ARCHS)) ifeq ($(GOHOSTARCH),amd64) ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux freebsd darwin windows)) # Only supported on amd64 test-flags := -race endif endif # This rule is used to forward a target like "build" to "common-build". This # allows a new "build" target to be defined in a Makefile which includes this # one and override "common-build" without override warnings. %: common-% ; .PHONY: common-all common-all: precheck style check_license lint yamllint unused build test .PHONY: common-style common-style: @echo ">> checking code style" @fmtRes=$$($(GOFMT) -d $$(find . -path ./vendor -prune -o -name '*.go' -print)); \ if [ -n "$${fmtRes}" ]; then \ echo "gofmt checking failed!"; echo "$${fmtRes}"; echo; \ echo "Please ensure you are using $$($(GO) version) for formatting code."; \ exit 1; \ fi .PHONY: common-check_license common-check_license: @echo ">> checking license header" @licRes=$$(for file in $$(find . -type f -iname '*.go' ! -path './vendor/*') ; do \ awk 'NR<=3' $$file | grep -Eq "(Copyright|generated|GENERATED)" || echo $$file; \ done); \ if [ -n "$${licRes}" ]; then \ echo "license header checking failed:"; echo "$${licRes}"; \ exit 1; \ fi .PHONY: common-deps common-deps: @echo ">> getting dependencies" ifdef GO111MODULE GO111MODULE=$(GO111MODULE) $(GO) mod download else $(GO) get $(GOOPTS) -t ./... endif .PHONY: update-go-deps update-go-deps: @echo ">> updating Go dependencies" @for m in $$($(GO) list -mod=readonly -m -f '{{ if and (not .Indirect) (not .Main)}}{{.Path}}{{end}}' all); do \ $(GO) get -d $$m; \ done GO111MODULE=$(GO111MODULE) $(GO) mod tidy ifneq (,$(wildcard vendor)) GO111MODULE=$(GO111MODULE) $(GO) mod vendor endif .PHONY: common-test-short common-test-short: $(GOTEST_DIR) @echo ">> running short tests" GO111MODULE=$(GO111MODULE) $(GOTEST) -short $(GOOPTS) $(pkgs) .PHONY: common-test common-test: $(GOTEST_DIR) @echo ">> running all tests" GO111MODULE=$(GO111MODULE) $(GOTEST) $(test-flags) $(GOOPTS) $(pkgs) $(GOTEST_DIR): @mkdir -p $@ .PHONY: common-format common-format: @echo ">> formatting code" GO111MODULE=$(GO111MODULE) $(GO) fmt $(pkgs) .PHONY: common-vet common-vet: @echo ">> vetting code" GO111MODULE=$(GO111MODULE) $(GO) vet $(GOOPTS) $(pkgs) .PHONY: common-lint common-lint: $(GOLANGCI_LINT) ifdef GOLANGCI_LINT @echo ">> running golangci-lint" ifdef GO111MODULE # 'go list' needs to be executed before staticcheck to prepopulate the modules cache. # Otherwise staticcheck might fail randomly for some reason not yet explained. GO111MODULE=$(GO111MODULE) $(GO) list -e -compiled -test=true -export=false -deps=true -find=false -tags= -- ./... > /dev/null GO111MODULE=$(GO111MODULE) $(GOLANGCI_LINT) run $(GOLANGCI_LINT_OPTS) $(pkgs) else $(GOLANGCI_LINT) run $(pkgs) endif endif .PHONY: common-yamllint common-yamllint: @echo ">> running yamllint on all YAML files in the repository" ifeq (, $(shell which yamllint)) @echo "yamllint not installed so skipping" else yamllint . endif # For backward-compatibility. .PHONY: common-staticcheck common-staticcheck: lint .PHONY: common-unused common-unused: $(GOVENDOR) ifdef GOVENDOR @echo ">> running check for unused packages" @$(GOVENDOR) list +unused | grep . && exit 1 || echo 'No unused packages' else ifdef GO111MODULE @echo ">> running check for unused/missing packages in go.mod" GO111MODULE=$(GO111MODULE) $(GO) mod tidy ifeq (,$(wildcard vendor)) @git diff --exit-code -- go.sum go.mod else @echo ">> running check for unused packages in vendor/" GO111MODULE=$(GO111MODULE) $(GO) mod vendor @git diff --exit-code -- go.sum go.mod vendor/ endif endif endif .PHONY: common-build common-build: promu @echo ">> building binaries" GO111MODULE=$(GO111MODULE) $(PROMU) build --prefix $(PREFIX) $(PROMU_BINARIES) .PHONY: common-tarball common-tarball: promu @echo ">> building release tarball" $(PROMU) tarball --prefix $(PREFIX) $(BIN_DIR) .PHONY: common-docker $(BUILD_DOCKER_ARCHS) common-docker: $(BUILD_DOCKER_ARCHS) $(BUILD_DOCKER_ARCHS): common-docker-%: docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" \ -f $(DOCKERFILE_PATH) \ --build-arg ARCH="$*" \ --build-arg OS="linux" \ $(DOCKERBUILD_CONTEXT) .PHONY: common-docker-publish $(PUBLISH_DOCKER_ARCHS) common-docker-publish: $(PUBLISH_DOCKER_ARCHS) $(PUBLISH_DOCKER_ARCHS): common-docker-publish-%: docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" DOCKER_MAJOR_VERSION_TAG = $(firstword $(subst ., ,$(shell cat VERSION))) .PHONY: common-docker-tag-latest $(TAG_DOCKER_ARCHS) common-docker-tag-latest: $(TAG_DOCKER_ARCHS) $(TAG_DOCKER_ARCHS): common-docker-tag-latest-%: docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:latest" docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:v$(DOCKER_MAJOR_VERSION_TAG)" .PHONY: common-docker-manifest common-docker-manifest: DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create -a "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" $(foreach ARCH,$(DOCKER_ARCHS),$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$(ARCH):$(DOCKER_IMAGE_TAG)) DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" .PHONY: promu promu: $(PROMU) $(PROMU): $(eval PROMU_TMP := $(shell mktemp -d)) curl -s -L $(PROMU_URL) | tar -xvzf - -C $(PROMU_TMP) mkdir -p $(FIRST_GOPATH)/bin cp $(PROMU_TMP)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM)/promu $(FIRST_GOPATH)/bin/promu rm -r $(PROMU_TMP) .PHONY: proto proto: @echo ">> generating code from proto files" @./scripts/genproto.sh ifdef GOLANGCI_LINT $(GOLANGCI_LINT): mkdir -p $(FIRST_GOPATH)/bin curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/$(GOLANGCI_LINT_VERSION)/install.sh \ | sed -e '/install -d/d' \ | sh -s -- -b $(FIRST_GOPATH)/bin $(GOLANGCI_LINT_VERSION) endif ifdef GOVENDOR .PHONY: $(GOVENDOR) $(GOVENDOR): GOOS= GOARCH= $(GO) get -u github.com/kardianos/govendor endif .PHONY: precheck precheck:: define PRECHECK_COMMAND_template = precheck:: $(1)_precheck PRECHECK_COMMAND_$(1) ?= $(1) $$(strip $$(PRECHECK_OPTIONS_$(1))) .PHONY: $(1)_precheck $(1)_precheck: @if ! $$(PRECHECK_COMMAND_$(1)) 1>/dev/null 2>&1; then \ echo "Execution of '$$(PRECHECK_COMMAND_$(1))' command failed. Is $(1) installed?"; \ exit 1; \ fi endef golang-github-prometheus-exporter-toolkit-0.7.1/README.md000066400000000000000000000022251415441071500232520ustar00rootroot00000000000000# Prometheus Exporter Toolkit [![CircleCI](https://circleci.com/gh/prometheus/exporter-toolkit/tree/master.svg?style=shield)][circleci] [![Go Report Card](https://goreportcard.com/badge/github.com/prometheus/exporter-toolkit)][goreportcard] [![go-doc](https://godoc.org/github.com/prometheus/exporter-toolkit?status.svg)][godoc] This is a [Go](http://golang.org) library for [Prometheus](http://prometheus.io) [exporters][exporter]. This repository is meant to be used in combination with the [client_golang][client_golang] repository. If you are [instrumenting][instrumentation] an existing Go application, [client_golang][client_golang] is the repository you are looking for. **This repository is currently WIP and experimental.** [circleci]:https://circleci.com/gh/prometheus/exporter-toolkit [client_golang]:https://github.com/prometheus/client_golang [exporter]:https://prometheus.io/docs/introduction/glossary/#exporter [godoc]:https://godoc.org/github.com/prometheus/exporter-toolkit [goreportcard]:https://goreportcard.com/report/github.com/prometheus/exporter-toolkit [instrumentation]:https://prometheus.io/docs/introduction/glossary/#direct-instrumentation golang-github-prometheus-exporter-toolkit-0.7.1/SECURITY.md000066400000000000000000000002521415441071500235620ustar00rootroot00000000000000# Reporting a security issue The Prometheus security policy, including how to report vulnerabilities, can be found here: https://prometheus.io/docs/operating/security/ golang-github-prometheus-exporter-toolkit-0.7.1/VERSION000066400000000000000000000000061415441071500230360ustar00rootroot000000000000000.7.1 golang-github-prometheus-exporter-toolkit-0.7.1/docs/000077500000000000000000000000001415441071500227225ustar00rootroot00000000000000golang-github-prometheus-exporter-toolkit-0.7.1/docs/introduction.md000066400000000000000000000006051415441071500257660ustar00rootroot00000000000000# Introduction The Prometheus Exporter Toolkit is a toolkit available to promote a common set of practices when developing in the Prometheus ecosystem. It is written in Golang. This documentation is the end user configuration. Developers documentation can be found on [pkg.go.dev](https://pkg.go.dev/github.com/prometheus/exporter-toolkit/). * [Web configuration](web-configuration.md) golang-github-prometheus-exporter-toolkit-0.7.1/docs/web-config.yml000066400000000000000000000010061415441071500254620ustar00rootroot00000000000000# TLS and basic authentication configuration example. # # Additionally, a certificate and a key file are needed. tls_server_config: cert_file: server.crt key_file: server.key # Usernames and passwords required to connect. # Passwords are hashed with bcrypt: https://github.com/prometheus/exporter-toolkit/blob/master/docs/web-configuration.md#about-bcrypt. basic_auth_users: alice: $2y$10$mDwo.lAisC94iLAyP81MCesa29IzH37oigHC/42V2pdJlUprsJPze bob: $2y$10$hLqFl9jSjoAAy95Z/zw8Ye8wkdMBM8c5Bn1ptYqP/AXyV0.oy0S8m golang-github-prometheus-exporter-toolkit-0.7.1/docs/web-configuration.md000066400000000000000000000122531415441071500266710ustar00rootroot00000000000000# Web configuration Exporters and services instrumented with the Exporter Toolkit share the same web configuration file format. This is *experimental* and might change in the future. To specify which web configuration file to load, use the `--web.config.file` flag. The file is written in [YAML format](https://en.wikipedia.org/wiki/YAML), defined by the scheme described below. Brackets indicate that a parameter is optional. For non-list parameters the value is set to the specified default. The file is read upon every http request, such as any change in the configuration, so the certificates are picked up immediately. Generic placeholders are defined as follows: * ``: a boolean that can take the values `true` or `false` * ``: a valid path in the current working directory * ``: a regular string that is a secret, such as a password * ``: a regular string ``` tls_server_config: # Certificate and key files for server to use to authenticate to client. cert_file: key_file: # Server policy for client authentication. Maps to ClientAuth Policies. # For more detail on clientAuth options: # https://golang.org/pkg/crypto/tls/#ClientAuthType # # NOTE: If you want to enable client authentication, you need to use # RequireAndVerifyClientCert. Other values are insecure. [ client_auth_type: | default = "NoClientCert" ] # CA certificate for client certificate authentication to the server. [ client_ca_file: ] # Minimum TLS version that is acceptable. [ min_version: | default = "TLS12" ] # Maximum TLS version that is acceptable. [ max_version: | default = "TLS13" ] # List of supported cipher suites for TLS versions up to TLS 1.2. If empty, # Go default cipher suites are used. Available cipher suites are documented # in the go documentation: # https://golang.org/pkg/crypto/tls/#pkg-constants [ cipher_suites: [ - ] ] # prefer_server_cipher_suites controls whether the server selects the # client's most preferred ciphersuite, or the server's most preferred # ciphersuite. If true then the server's preference, as expressed in # the order of elements in cipher_suites, is used. [ prefer_server_cipher_suites: | default = true ] # Elliptic curves that will be used in an ECDHE handshake, in preference # order. Available curves are documented in the go documentation: # https://golang.org/pkg/crypto/tls/#CurveID [ curve_preferences: [ - ] ] http_server_config: # Enable HTTP/2 support. Note that HTTP/2 is only supported with TLS. # This can not be changed on the fly. [ http2: | default = true ] # List of headers that can be added to HTTP responses. [ headers: # Set the Content-Security-Policy header to HTTP responses. # Unset if blank. [ Content-Security-Policy: ] # Set the X-Frame-Options header to HTTP responses. # Unset if blank. Accepted values are deny and sameorigin. # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options [ X-Frame-Options: ] # Set the X-Content-Type-Options header to HTTP responses. # Unset if blank. Accepted value is nosniff. # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options [ X-Content-Type-Options: ] # Set the X-XSS-Protection header to all responses. # Unset if blank. Accepted value is nosniff. # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection [ X-XSS-Protection: ] # Set the Strict-Transport-Security header to HTTP responses. # Unset if blank. # Please make sure that you use this with care as this header might force # browsers to load Prometheus and the other applications hosted on the same # domain and subdomains over HTTPS. # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security [ Strict-Transport-Security: ] ] # Usernames and hashed passwords that have full access to the web # server via basic authentication. If empty, no basic authentication is # required. Passwords are hashed with bcrypt. basic_auth_users: [ : ... ] ``` [A sample configuration file](web-config.yml) is provided. ## About bcrypt There are several tools out there to generate bcrypt passwords, e.g. [htpasswd](https://httpd.apache.org/docs/2.4/programs/htpasswd.html): `htpasswd -nBC 10 "" | tr -d ':\n'` That command will prompt you for a password and output the hashed password, which will look something like: `$2y$10$X0h1gDsPszWURQaxFh.zoubFi6DXncSjhoQNJgRrnGs7EsimhC7zG` The cost (10 in the example) influences the time it takes for computing the hash. A higher cost will end up slowing down the authentication process. Depending on the machine, a cost of 10 will take about ~70ms, whereas a cost of 18 can take up to a few seconds. That hash will be computed on the first authenticated HTTP request and then cached. ## Performance Basic authentication is meant for simple use cases, with a few users. If you need to authenticate a lot of users, it is recommended to use TLS client certificates, or to use a proper reverse proxy to handle the authentication. golang-github-prometheus-exporter-toolkit-0.7.1/go.mod000066400000000000000000000004361415441071500231030ustar00rootroot00000000000000module github.com/prometheus/exporter-toolkit go 1.14 require ( github.com/go-kit/log v0.1.0 github.com/pkg/errors v0.9.1 github.com/prometheus/common v0.29.0 golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e gopkg.in/alecthomas/kingpin.v2 v2.2.6 gopkg.in/yaml.v2 v2.4.0 ) golang-github-prometheus-exporter-toolkit-0.7.1/go.sum000066400000000000000000001353061415441071500231350ustar00rootroot00000000000000cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= 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/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 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/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0 h1:DGJh0Sm43HbOeYDNnVZFl8BvcYVvjD5bqYJvp0REbwQ= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= 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-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= 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/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= 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.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/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.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= 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/konsorten/go-windows-terminal-sequences v1.0.3/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/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/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-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.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 v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= 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/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.29.0 h1:3jqPBvKT4OHAbje2Ql7KeaaSicDBCxMYwEJU1zRJceE= github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= 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/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 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-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/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-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 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-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/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-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/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-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c h1:pkQiBZBvdos9qq4wBAHqlzuZHEXo07pqV06ef90u1WI= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 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-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/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-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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 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.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/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-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 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= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1 h1:7QnIQpGRHE5RnLKnESfDoxm2dTapTZua5a0kS0A+VXQ= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= 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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 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.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= golang-github-prometheus-exporter-toolkit-0.7.1/scripts/000077500000000000000000000000001415441071500234615ustar00rootroot00000000000000golang-github-prometheus-exporter-toolkit-0.7.1/scripts/errcheck_excludes.txt000066400000000000000000000002521415441071500277030ustar00rootroot00000000000000// Used in HTTP handlers, any error is handled by the server itself. (net/http.ResponseWriter).Write // Never check for logger errors. (github.com/go-kit/log.Logger).Log golang-github-prometheus-exporter-toolkit-0.7.1/web/000077500000000000000000000000001415441071500225475ustar00rootroot00000000000000golang-github-prometheus-exporter-toolkit-0.7.1/web/README.md000066400000000000000000000005141415441071500240260ustar00rootroot00000000000000# web package This package can be used by Prometheus exporters to enable TLS and authentication. We actively encourage the community to use this repository, to provide a consistent experience across the ecosystem. Developers documentation can be found on [pkg.go.dev](https://pkg.go.dev/github.com/prometheus/exporter-toolkit/). golang-github-prometheus-exporter-toolkit-0.7.1/web/cache.go000066400000000000000000000051261415441071500241450ustar00rootroot00000000000000// Copyright 2021 The Prometheus Authors // This code is partly borrowed from Caddy: // Copyright 2015 Matthew Holt and The Caddy Authors // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package web import ( weakrand "math/rand" "sync" "time" ) var cacheSize = 100 func init() { weakrand.Seed(time.Now().UnixNano()) } type cache struct { cache map[string]bool mtx sync.Mutex } // newCache returns a cache that contains a mapping of plaintext passwords // to their hashes (with random eviction). This can greatly improve the // performance of traffic-heavy servers that use secure password hashing // algorithms, with the downside that plaintext passwords will be stored in // memory for a longer time (this should not be a problem as long as your // machine is not compromised, at which point all bets are off, since basicauth // necessitates plaintext passwords being received over the wire anyway). func newCache() *cache { return &cache{ cache: make(map[string]bool), } } func (c *cache) get(key string) (bool, bool) { c.mtx.Lock() defer c.mtx.Unlock() v, ok := c.cache[key] return v, ok } func (c *cache) set(key string, value bool) { c.mtx.Lock() defer c.mtx.Unlock() c.makeRoom() c.cache[key] = value } func (c *cache) makeRoom() { if len(c.cache) < cacheSize { return } // We delete more than just 1 entry so that we don't have // to do this on every request; assuming the capacity of // the cache is on a long tail, we can save a lot of CPU // time by doing a whole bunch of deletions now and then // we won't have to do them again for a while. numToDelete := len(c.cache) / 10 if numToDelete < 1 { numToDelete = 1 } for deleted := 0; deleted <= numToDelete; deleted++ { // Go maps are "nondeterministic" not actually random, // so although we could just chop off the "front" of the // map with less code, this is a heavily skewed eviction // strategy; generating random numbers is cheap and // ensures a much better distribution. rnd := weakrand.Intn(len(c.cache)) i := 0 for key := range c.cache { if i == rnd { delete(c.cache, key) break } i++ } } } golang-github-prometheus-exporter-toolkit-0.7.1/web/cache_test.go000066400000000000000000000021211415441071500251740ustar00rootroot00000000000000// Copyright 2021 The Prometheus Authors // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package web import ( "fmt" "testing" ) // TestCacheSize validates that makeRoom function caps the size of the cache // appropriately. func TestCacheSize(t *testing.T) { cache := newCache() expectedSize := 0 for i := 0; i < 200; i++ { cache.set(fmt.Sprintf("foo%d", i), true) expectedSize++ if expectedSize > 100 { expectedSize = 90 } if gotSize := len(cache.cache); gotSize != expectedSize { t.Fatalf("iter %d: cache size invalid: expected %d, got %d", i, expectedSize, gotSize) } } } golang-github-prometheus-exporter-toolkit-0.7.1/web/handler.go000066400000000000000000000073501415441071500245200ustar00rootroot00000000000000// Copyright 2020 The Prometheus Authors // This code is partly borrowed from Caddy: // Copyright 2015 Matthew Holt and The Caddy Authors // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package web import ( "encoding/hex" "fmt" "net/http" "sync" "github.com/go-kit/log" "golang.org/x/crypto/bcrypt" ) // extraHTTPHeaders is a map of HTTP headers that can be added to HTTP // responses. // This is private on purpose to ensure consistency in the Prometheus ecosystem. var extraHTTPHeaders = map[string][]string{ "Strict-Transport-Security": nil, "X-Content-Type-Options": {"nosniff"}, "X-Frame-Options": {"deny", "sameorigin"}, "X-XSS-Protection": nil, "Content-Security-Policy": nil, } func validateUsers(configPath string) error { c, err := getConfig(configPath) if err != nil { return err } for _, p := range c.Users { _, err = bcrypt.Cost([]byte(p)) if err != nil { return err } } return nil } // validateHeaderConfig checks that the provided header configuration is correct. // It does not check the validity of all the values, only the ones which are // well-defined enumerations. func validateHeaderConfig(headers map[string]string) error { HeadersLoop: for k, v := range headers { values, ok := extraHTTPHeaders[k] if !ok { return fmt.Errorf("HTTP header %q can not be configured", k) } for _, allowedValue := range values { if v == allowedValue { continue HeadersLoop } } if len(values) > 0 { return fmt.Errorf("invalid value for %s. Expected one of: %q, but got: %q", k, values, v) } } return nil } type webHandler struct { tlsConfigPath string handler http.Handler logger log.Logger cache *cache // bcryptMtx is there to ensure that bcrypt.CompareHashAndPassword is run // only once in parallel as this is CPU intensive. bcryptMtx sync.Mutex } func (u *webHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { c, err := getConfig(u.tlsConfigPath) if err != nil { u.logger.Log("msg", "Unable to parse configuration", "err", err) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } // Configure http headers. for k, v := range c.HTTPConfig.Header { w.Header().Set(k, v) } if len(c.Users) == 0 { u.handler.ServeHTTP(w, r) return } user, pass, auth := r.BasicAuth() if auth { hashedPassword, validUser := c.Users[user] if !validUser { // The user is not found. Use a fixed password hash to // prevent user enumeration by timing requests. // This is a bcrypt-hashed version of "fakepassword". hashedPassword = "$2y$10$QOauhQNbBCuQDKes6eFzPeMqBSjb7Mr5DUmpZ/VcEd00UAV/LDeSi" } cacheKey := hex.EncodeToString(append(append([]byte(user), []byte(hashedPassword)...), []byte(pass)...)) authOk, ok := u.cache.get(cacheKey) if !ok { // This user, hashedPassword, password is not cached. u.bcryptMtx.Lock() err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(pass)) u.bcryptMtx.Unlock() authOk = err == nil u.cache.set(cacheKey, authOk) } if authOk && validUser { u.handler.ServeHTTP(w, r) return } } w.Header().Set("WWW-Authenticate", "Basic") http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) } golang-github-prometheus-exporter-toolkit-0.7.1/web/handler_test.go000066400000000000000000000100761415441071500255560ustar00rootroot00000000000000// Copyright 2021 The Prometheus Authors // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package web import ( "context" "net/http" "sync" "testing" ) // TestBasicAuthCache validates that the cache is working by calling a password // protected endpoint multiple times. func TestBasicAuthCache(t *testing.T) { server := &http.Server{ Addr: port, Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello World!")) }), } done := make(chan struct{}) t.Cleanup(func() { if err := server.Shutdown(context.Background()); err != nil { t.Fatal(err) } <-done }) go func() { ListenAndServe(server, "testdata/web_config_users_noTLS.good.yml", testlogger) close(done) }() login := func(username, password string, code int) { client := &http.Client{} req, err := http.NewRequest("GET", "http://localhost"+port, nil) if err != nil { t.Fatal(err) } req.SetBasicAuth(username, password) r, err := client.Do(req) if err != nil { t.Fatal(err) } if r.StatusCode != code { t.Fatalf("bad return code, expected %d, got %d", code, r.StatusCode) } } // Initial logins, checking that it just works. login("alice", "alice123", 200) login("alice", "alice1234", 401) var ( start = make(chan struct{}) wg sync.WaitGroup ) wg.Add(300) for i := 0; i < 150; i++ { go func() { <-start login("alice", "alice123", 200) wg.Done() }() go func() { <-start login("alice", "alice1234", 401) wg.Done() }() } close(start) wg.Wait() } // TestBasicAuthWithFakePassword validates that we can't login the "fakepassword" used in // to prevent user enumeration. func TestBasicAuthWithFakepassword(t *testing.T) { server := &http.Server{ Addr: port, Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello World!")) }), } done := make(chan struct{}) t.Cleanup(func() { if err := server.Shutdown(context.Background()); err != nil { t.Fatal(err) } <-done }) go func() { ListenAndServe(server, "testdata/web_config_users_noTLS.good.yml", testlogger) close(done) }() login := func() { client := &http.Client{} req, err := http.NewRequest("GET", "http://localhost"+port, nil) if err != nil { t.Fatal(err) } req.SetBasicAuth("fakeuser", "fakepassword") r, err := client.Do(req) if err != nil { t.Fatal(err) } if r.StatusCode != 401 { t.Fatalf("bad return code, expected %d, got %d", 401, r.StatusCode) } } // Login with a cold cache. login() // Login with the response cached. login() } // TestHTTPHeaders validates that HTTP headers are added correctly. func TestHTTPHeaders(t *testing.T) { server := &http.Server{ Addr: port, Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello World!")) }), } done := make(chan struct{}) t.Cleanup(func() { if err := server.Shutdown(context.Background()); err != nil { t.Fatal(err) } <-done }) go func() { ListenAndServe(server, "testdata/web_config_headers.good.yml", testlogger) close(done) }() client := &http.Client{} req, err := http.NewRequest("GET", "http://localhost"+port, nil) if err != nil { t.Fatal(err) } r, err := client.Do(req) if err != nil { t.Fatal(err) } for k, v := range map[string]string{ "Strict-Transport-Security": "max-age=31536000; includeSubDomains", "X-Frame-Options": "deny", "X-Content-Type-Options": "nosniff", "X-XSS-Protection": "1", } { if got := r.Header.Get(k); got != v { t.Fatalf("unexpected %s header value, expected %q, got %q", k, v, got) } } } golang-github-prometheus-exporter-toolkit-0.7.1/web/kingpinflag/000077500000000000000000000000001415441071500250405ustar00rootroot00000000000000golang-github-prometheus-exporter-toolkit-0.7.1/web/kingpinflag/flag.go000066400000000000000000000017621415441071500263060ustar00rootroot00000000000000// Copyright 2020 The Prometheus Authors // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package kingpinflag import ( "gopkg.in/alecthomas/kingpin.v2" ) // AddFlags adds the flags used by this package to the Kingpin application. // To use the default Kingpin application, call AddFlags(kingpin.CommandLine) func AddFlags(a *kingpin.Application) *string { return a.Flag( "web.config.file", "[EXPERIMENTAL] Path to configuration file that can enable TLS or authentication.", ).Default("").String() } golang-github-prometheus-exporter-toolkit-0.7.1/web/testdata/000077500000000000000000000000001415441071500243605ustar00rootroot00000000000000golang-github-prometheus-exporter-toolkit-0.7.1/web/testdata/server.crt000066400000000000000000000120251415441071500264000ustar00rootroot00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 1 (0x1) Signature Algorithm: sha1WithRSAEncryption Issuer: C=US, O=Prometheus, OU=Prometheus Certificate Authority, CN=Prometheus TLS CA Validity Not Before: Apr 5 08:06:57 2019 GMT Not After : Mar 26 08:06:57 2059 GMT Subject: C=US, O=Prometheus, CN=prometheus.example.com Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (2048 bit) Modulus: 00:bd:6c:b6:7f:d1:2f:be:e4:41:eb:5d:ff:50:78: 03:2b:76:03:da:01:48:20:13:90:66:c9:ce:6e:06: e5:fa:2d:0d:c0:b0:46:28:44:10:a0:61:79:87:a2: 98:4c:29:fa:f9:bb:0f:44:c7:90:5c:5c:55:60:cd: 45:da:b8:e4:dd:28:72:c8:8b:a1:3e:4b:00:09:82: b0:2c:dc:d6:17:c9:02:f4:cd:26:c7:11:28:f3:77: b5:97:c2:76:c2:e0:07:d7:34:5b:e0:ed:1a:59:a5: b4:b7:16:09:3d:35:bd:d9:03:07:9d:7c:3b:f0:63: bd:5e:02:99:cf:32:e1:ac:4c:7a:3e:4c:b2:8e:98: 68:07:4f:59:dc:0d:bf:cc:83:04:5c:d8:90:f0:73: da:2b:08:17:c4:36:a7:d8:94:3d:b6:c0:af:29:0a: d3:19:5f:eb:7d:cc:4d:05:56:11:0a:ee:b1:f3:d7: c9:5a:3c:8c:57:16:91:51:14:f8:20:4e:0f:29:9e: 04:21:e6:f1:e4:e8:44:af:d7:25:92:08:64:fc:2c: 1c:2e:4f:71:53:91:53:1d:e5:f9:7b:52:0f:21:da: 5c:dd:19:68:96:ca:70:6a:f1:c4:0d:07:af:f8:65: 13:92:e9:ef:65:b3:89:86:fd:c0:74:5c:a4:6b:49: 62:c5 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Key Usage: critical Digital Signature, Key Encipherment X509v3 Basic Constraints: CA:FALSE X509v3 Extended Key Usage: TLS Web Server Authentication, TLS Web Client Authentication X509v3 Subject Key Identifier: 00:61:01:AD:25:44:8A:EF:E1:2C:EC:83:5A:3A:3B:EA:A0:BD:E1:45 X509v3 Authority Key Identifier: keyid:4D:02:BF:71:95:6A:AA:58:C5:9C:B8:83:67:5E:64:16:99:E1:2A:9E Authority Information Access: CA Issuers - URI:http://example.com/ca/tls-ca.cer X509v3 CRL Distribution Points: Full Name: URI:http://example.com/ca/tls-ca.crl X509v3 Subject Alternative Name: IP Address:127.0.0.1, IP Address:127.0.0.0, DNS:localhost Signature Algorithm: sha1WithRSAEncryption 77:97:e4:ef:db:10:8e:62:50:96:4a:6e:f5:a4:f9:1f:19:3b: c8:a4:dd:b3:f6:11:41:1a:fb:e3:f8:dd:0e:64:e5:2b:00:b9: e6:25:9f:2e:e1:d2:9a:cd:b6:f2:41:4d:27:dd:2c:9a:af:97: 79:e8:cf:61:fb:cf:be:25:c6:e1:19:a0:c8:90:44:a0:76:8a: 45:d4:37:22:e5:d4:80:b4:b3:0f:a8:33:08:24:ad:21:0b:b7: 98:46:93:90:8a:ae:77:0c:cb:b8:59:d3:3b:9b:fb:16:5a:22: ca:c2:97:9d:78:1b:fc:23:fc:a0:42:54:40:de:88:4b:07:2b: 19:4e:0e:79:bf:c9:9f:01:a6:46:c5:55:fa:9f:c0:0d:8a:a6: e1:47:16:a6:0e:be:23:c9:e9:58:d6:31:71:8c:80:9c:16:64: f0:14:08:22:a1:23:7c:98:b9:62:d1:4a:ce:e3:5c:59:fb:41: 87:a5:3b:36:dd:3d:45:48:b0:b0:77:6f:de:58:2a:27:4d:56: 20:54:08:20:c8:6d:79:b5:b9:e6:3a:03:24:0f:6d:67:39:20: 78:10:2f:47:85:83:c1:4d:17:33:79:84:75:27:fa:47:67:59: 56:cc:33:7b:a5:77:aa:59:9a:98:30:10:1a:78:43:34:8f:ed: c2:a1:a3:ea -----BEGIN CERTIFICATE----- MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADBpMQswCQYDVQQGEwJVUzET MBEGA1UECgwKUHJvbWV0aGV1czEpMCcGA1UECwwgUHJvbWV0aGV1cyBDZXJ0aWZp Y2F0ZSBBdXRob3JpdHkxGjAYBgNVBAMMEVByb21ldGhldXMgVExTIENBMCAXDTE5 MDQwNTA4MDY1N1oYDzIwNTkwMzI2MDgwNjU3WjBDMQswCQYDVQQGEwJVUzETMBEG A1UECgwKUHJvbWV0aGV1czEfMB0GA1UEAwwWcHJvbWV0aGV1cy5leGFtcGxlLmNv bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL1stn/RL77kQetd/1B4 Ayt2A9oBSCATkGbJzm4G5fotDcCwRihEEKBheYeimEwp+vm7D0THkFxcVWDNRdq4 5N0ocsiLoT5LAAmCsCzc1hfJAvTNJscRKPN3tZfCdsLgB9c0W+DtGlmltLcWCT01 vdkDB518O/BjvV4Cmc8y4axMej5Mso6YaAdPWdwNv8yDBFzYkPBz2isIF8Q2p9iU PbbArykK0xlf633MTQVWEQrusfPXyVo8jFcWkVEU+CBODymeBCHm8eToRK/XJZII ZPwsHC5PcVORUx3l+XtSDyHaXN0ZaJbKcGrxxA0Hr/hlE5Lp72WziYb9wHRcpGtJ YsUCAwEAAaOCAREwggENMA4GA1UdDwEB/wQEAwIFoDAJBgNVHRMEAjAAMB0GA1Ud JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUAGEBrSVEiu/hLOyD Wjo76qC94UUwHwYDVR0jBBgwFoAUTQK/cZVqqljFnLiDZ15kFpnhKp4wPAYIKwYB BQUHAQEEMDAuMCwGCCsGAQUFBzAChiBodHRwOi8vZXhhbXBsZS5jb20vY2EvdGxz LWNhLmNlcjAxBgNVHR8EKjAoMCagJKAihiBodHRwOi8vZXhhbXBsZS5jb20vY2Ev dGxzLWNhLmNybDAgBgNVHREEGTAXhwR/AAABhwR/AAAAgglsb2NhbGhvc3QwDQYJ KoZIhvcNAQEFBQADggEBAHeX5O/bEI5iUJZKbvWk+R8ZO8ik3bP2EUEa++P43Q5k 5SsAueYlny7h0prNtvJBTSfdLJqvl3noz2H7z74lxuEZoMiQRKB2ikXUNyLl1IC0 sw+oMwgkrSELt5hGk5CKrncMy7hZ0zub+xZaIsrCl514G/wj/KBCVEDeiEsHKxlO Dnm/yZ8BpkbFVfqfwA2KpuFHFqYOviPJ6VjWMXGMgJwWZPAUCCKhI3yYuWLRSs7j XFn7QYelOzbdPUVIsLB3b95YKidNViBUCCDIbXm1ueY6AyQPbWc5IHgQL0eFg8FN FzN5hHUn+kdnWVbMM3uld6pZmpgwEBp4QzSP7cKho+o= -----END CERTIFICATE----- golang-github-prometheus-exporter-toolkit-0.7.1/web/testdata/server.key000066400000000000000000000032501415441071500264000ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC9bLZ/0S++5EHr Xf9QeAMrdgPaAUggE5Bmyc5uBuX6LQ3AsEYoRBCgYXmHophMKfr5uw9Ex5BcXFVg zUXauOTdKHLIi6E+SwAJgrAs3NYXyQL0zSbHESjzd7WXwnbC4AfXNFvg7RpZpbS3 Fgk9Nb3ZAwedfDvwY71eApnPMuGsTHo+TLKOmGgHT1ncDb/MgwRc2JDwc9orCBfE NqfYlD22wK8pCtMZX+t9zE0FVhEK7rHz18laPIxXFpFRFPggTg8pngQh5vHk6ESv 1yWSCGT8LBwuT3FTkVMd5fl7Ug8h2lzdGWiWynBq8cQNB6/4ZROS6e9ls4mG/cB0 XKRrSWLFAgMBAAECggEAezQ0V1o11dEc1vuiTjJgzWnLA4aF5OcUquZjb8jo2Blp soR0fUgYEFiV9RRaPl+nr7ptKe0rBgfAOGALKUHNCdN/JNU8oQmjEoyADg3s6jeB xruQlzWgDwszf2uqVwHj16Nkhx1wYBKZQeQBSmCkBHwl/daKHcahqn3CkLOleKx+ Qlc3BzWNaGte6qpJMs0It3by1FuxRwVz5VkL8uhzj0WIOYMA84t0gTnFH9gfRO3F licotxg/Nl5M36wWcfL8Jq++72AtaKcD1jUEwuQpogrVeqflmeHwn/TlL++Hv6Xe Lq0jt3OCUKUV40eq9c5uEgTmyrVHMDkfFdXzutdMAQKBgQDsSMXk7P4SX6u6uTjV In9eWw6ZyJ2aL6VB9co/NMsj49GrrFT8VX9d+JPe9P/n6tuGcFbymNep22njRksR 0ItpW1NFRR/R3g0kYe1EhkRpNm6fhY9oIuR9xhcNnPNYkqAKT3T/dxrzbwsNhomi X8aht/eCz4ZsK/KdOGTkPozxgQKBgQDNOvrclT1Wl4bxONp9pEV5XpRSD/qigfIp i5wxy7ihX/QY9RToIWJDnzMVLnEYe64RB2WB8/4WwNPOQcuaxXbFUFct/2NdhTnS ToJPgPe819zW9t1FLTf1fHtsRBpGFtbhdlUDOiOtJiMXYiwlRh2uyWFhjOo8TNUE qMwai0vLRQKBgQCDH4t6lC4W4jK5x2oLlT5bjWqX2uXjF8e8x/q5gsGspBPKEjOD aKrq6jSdSRbui73RaGxH6pvb7iBf+LVWKIYFLKIUUdzrqS9f3lw+Z8h1HrjbG9JO dvaX+aL3cf71S0E3F4sU7fLt3tSiZ+PfUQk424+mbyXox6a2qwIKS9AJgQKBgHCu dHROYJo9ojKpo5Ueb6K+4jLYYSV+sYZMCBtzHlFETNKzJaJ6SeiU7Ugw8pmdtqnU 5M/gNl8pymFR0MeOqbKWdPdlZJpBfsjQoE2kouEFqFRCwKStui7IBUAheEeJXLv3 659U+aek69l35oMkp0GDgjs8UpN/H+pp/36Hgrr9AoGAftWU405rpStHEdRVrazP FibQesT9HOdJgmm1gNIhj+PnFs7lKER9p0Wdl79QnIqjwyhjCXL94TFerzTKLY2c IRj5dcRHiiT0iK8wq8bzGNYCqV73oQXaUFMiutNAArXwzwuvPFPWNBQsjLzeDLeC mcOsCcPAk8cLYtVfZo2sP3g= -----END PRIVATE KEY----- golang-github-prometheus-exporter-toolkit-0.7.1/web/testdata/tls-ca-chain.pem000066400000000000000000000223441415441071500273330ustar00rootroot00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 2 (0x2) Signature Algorithm: sha1WithRSAEncryption Issuer: C=US, O=Prometheus, OU=Prometheus Certificate Authority, CN=Prometheus Root CA Validity Not Before: Apr 5 08:00:37 2019 GMT Not After : Mar 26 08:00:37 2059 GMT Subject: C=US, O=Prometheus, OU=Prometheus Certificate Authority, CN=Prometheus TLS CA Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (2048 bit) Modulus: 00:aa:d2:34:6b:ed:f1:f4:01:08:e5:00:9f:75:c8: ba:fc:4b:72:c6:04:93:af:f1:f6:b5:ce:01:0d:c6: bd:d3:16:98:9d:e5:51:56:12:58:16:ee:18:6e:f0: 68:a9:42:16:65:cf:e3:31:f5:90:79:9d:13:32:87: 3b:1f:65:fd:84:88:a4:56:3d:26:54:69:05:27:5a: ea:89:02:e7:31:9b:7d:7f:76:93:54:70:bc:17:92: 06:9f:9f:90:4a:8a:cf:82:a7:7b:7c:71:c4:fa:34: 56:00:32:1a:85:c5:f8:e4:4a:63:43:37:9d:60:84: 4d:78:6e:87:12:c4:2b:1f:93:a5:fe:cc:5e:f1:df: c1:97:ff:b7:3e:20:38:1d:71:15:11:ec:6c:7a:cc: 0e:87:52:31:b1:b9:74:c3:07:1c:42:4b:1e:c1:17: bc:e4:13:b7:b0:20:2e:c4:07:93:bd:a8:11:f9:da: a7:d0:df:4a:48:be:9b:6d:65:c3:ae:58:56:c0:9f: 17:c5:d8:32:b1:04:22:fb:5b:18:f6:20:10:50:ec: 2d:10:4f:cc:48:8f:f2:75:dd:33:a4:0e:f5:55:da: 2c:89:a1:3a:52:bb:11:11:0b:97:27:17:73:35:da: 10:71:b3:9f:a8:42:91:e6:3a:66:00:f9:e5:11:8f: 5b:57 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Key Usage: critical Certificate Sign, CRL Sign X509v3 Basic Constraints: critical CA:TRUE, pathlen:0 X509v3 Subject Key Identifier: 4D:02:BF:71:95:6A:AA:58:C5:9C:B8:83:67:5E:64:16:99:E1:2A:9E X509v3 Authority Key Identifier: keyid:3C:1E:A8:C6:4C:05:4D:20:EC:88:DB:29:D4:7B:F9:12:5D:CE:EA:1A Authority Information Access: CA Issuers - URI:https://example.com/ca/root-ca.cer X509v3 CRL Distribution Points: Full Name: URI:https://example.com/ca/root-ca.crl Signature Algorithm: sha1WithRSAEncryption 63:fc:ba:30:a5:05:d6:76:14:f1:77:38:b1:41:6f:81:d9:b4: 02:fd:bc:e5:f6:d9:e6:73:e0:71:cf:4c:fb:13:b5:6b:bd:b9: c6:f6:28:18:36:e1:8c:d9:93:b3:78:4a:3d:39:1b:f4:fb:69: 75:24:ae:e1:a0:2f:94:05:bf:10:3c:3e:d2:2b:a8:f3:31:25: 2e:ed:13:ad:60:5d:22:9a:26:15:20:86:98:73:4c:f6:4b:48: b8:1f:67:ba:4e:c9:47:ed:85:dc:38:dc:02:0c:fb:54:d5:2e: 6c:b4:95:18:51:d1:ae:ea:e8:fb:b4:19:50:04:bc:31:7e:51: 9e:85:29:4d:c8:f7:26:d6:d6:8d:35:2d:9e:e2:06:16:38:e2: 56:80:ec:f3:a3:34:e3:28:c4:e8:10:d0:8a:a6:6f:20:9a:b9: dc:b9:90:6b:ba:8a:27:2c:29:72:28:55:e7:59:a6:a7:90:ec: 32:e8:d0:26:4a:c1:44:dd:20:bf:dc:4d:1e:7e:cc:e5:a2:5b: e8:df:3d:4b:01:aa:48:56:17:e9:29:d8:71:83:05:36:8c:11: 4f:77:b8:95:20:b7:c7:21:06:c2:87:97:b4:6b:d3:f7:23:ba: 4d:5f:15:d1:0c:4d:6e:f1:6a:9d:57:5c:02:6a:d7:31:18:ef: 5c:fc:f8:04 -----BEGIN CERTIFICATE----- MIIELTCCAxWgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBqMQswCQYDVQQGEwJVUzET MBEGA1UECgwKUHJvbWV0aGV1czEpMCcGA1UECwwgUHJvbWV0aGV1cyBDZXJ0aWZp Y2F0ZSBBdXRob3JpdHkxGzAZBgNVBAMMElByb21ldGhldXMgUm9vdCBDQTAgFw0x OTA0MDUwODAwMzdaGA8yMDU5MDMyNjA4MDAzN1owaTELMAkGA1UEBhMCVVMxEzAR BgNVBAoMClByb21ldGhldXMxKTAnBgNVBAsMIFByb21ldGhldXMgQ2VydGlmaWNh dGUgQXV0aG9yaXR5MRowGAYDVQQDDBFQcm9tZXRoZXVzIFRMUyBDQTCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKrSNGvt8fQBCOUAn3XIuvxLcsYEk6/x 9rXOAQ3GvdMWmJ3lUVYSWBbuGG7waKlCFmXP4zH1kHmdEzKHOx9l/YSIpFY9JlRp BSda6okC5zGbfX92k1RwvBeSBp+fkEqKz4Kne3xxxPo0VgAyGoXF+ORKY0M3nWCE TXhuhxLEKx+Tpf7MXvHfwZf/tz4gOB1xFRHsbHrMDodSMbG5dMMHHEJLHsEXvOQT t7AgLsQHk72oEfnap9DfSki+m21lw65YVsCfF8XYMrEEIvtbGPYgEFDsLRBPzEiP 8nXdM6QO9VXaLImhOlK7ERELlycXczXaEHGzn6hCkeY6ZgD55RGPW1cCAwEAAaOB 3DCB2TAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4E FgQUTQK/cZVqqljFnLiDZ15kFpnhKp4wHwYDVR0jBBgwFoAUPB6oxkwFTSDsiNsp 1Hv5El3O6howPgYIKwYBBQUHAQEEMjAwMC4GCCsGAQUFBzAChiJodHRwczovL2V4 YW1wbGUuY29tL2NhL3Jvb3QtY2EuY2VyMDMGA1UdHwQsMCowKKAmoCSGImh0dHBz Oi8vZXhhbXBsZS5jb20vY2Evcm9vdC1jYS5jcmwwDQYJKoZIhvcNAQEFBQADggEB AGP8ujClBdZ2FPF3OLFBb4HZtAL9vOX22eZz4HHPTPsTtWu9ucb2KBg24YzZk7N4 Sj05G/T7aXUkruGgL5QFvxA8PtIrqPMxJS7tE61gXSKaJhUghphzTPZLSLgfZ7pO yUfthdw43AIM+1TVLmy0lRhR0a7q6Pu0GVAEvDF+UZ6FKU3I9ybW1o01LZ7iBhY4 4laA7POjNOMoxOgQ0IqmbyCaudy5kGu6iicsKXIoVedZpqeQ7DLo0CZKwUTdIL/c TR5+zOWiW+jfPUsBqkhWF+kp2HGDBTaMEU93uJUgt8chBsKHl7Rr0/cjuk1fFdEM TW7xap1XXAJq1zEY71z8+AQ= -----END CERTIFICATE----- Certificate: Data: Version: 3 (0x2) Serial Number: 1 (0x1) Signature Algorithm: sha1WithRSAEncryption Issuer: C=US, O=Prometheus, OU=Prometheus Certificate Authority, CN=Prometheus Root CA Validity Not Before: Apr 5 07:55:00 2019 GMT Not After : Mar 26 07:55:00 2059 GMT Subject: C=US, O=Prometheus, OU=Prometheus Certificate Authority, CN=Prometheus Root CA Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (2048 bit) Modulus: 00:bf:b9:e2:ab:5f:61:22:e1:4e:cd:ee:da:b0:26: 2e:bb:b0:7e:1c:ce:10:be:16:29:35:0c:0c:1d:93: 01:29:2a:f6:f9:c2:6e:5c:10:44:ca:f8:dc:ad:7a: 06:64:0f:8a:18:ad:b2:a2:94:49:c9:ba:8c:45:94: 7c:d9:e0:11:45:d8:16:79:a2:20:9f:8c:63:60:72: 2a:5b:f9:66:80:ac:85:67:01:5a:eb:91:c1:d2:88: 87:9e:4c:18:c9:f2:f0:7a:18:c0:e6:ab:2c:78:de: 5f:b2:22:4e:94:9c:f5:cd:e6:e2:33:30:e9:20:10: a6:a1:75:eb:59:ab:45:a9:f7:3e:54:40:ae:05:25: be:74:c5:3a:fd:af:73:16:60:45:7c:4a:e0:0e:0d: a1:15:7f:9a:1f:c2:a7:04:ad:ef:b3:e4:f6:00:2c: 4e:0b:04:90:49:ee:d3:db:a6:12:c4:91:0b:32:4f: 11:84:c7:c4:8a:ef:51:66:7a:b0:20:2f:cb:95:8d: 96:57:60:66:5e:f9:4f:5a:94:9c:71:ad:eb:ca:70: 3e:62:06:c2:3a:29:f8:9e:86:af:da:07:78:f8:31: af:42:48:49:9e:4a:df:1b:27:1f:44:35:81:6d:fa: 7a:c5:6a:0a:35:23:c7:c4:d5:fe:c9:9e:61:c9:30: cd:1f Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Key Usage: critical Certificate Sign, CRL Sign X509v3 Basic Constraints: critical CA:TRUE X509v3 Subject Key Identifier: 3C:1E:A8:C6:4C:05:4D:20:EC:88:DB:29:D4:7B:F9:12:5D:CE:EA:1A X509v3 Authority Key Identifier: keyid:3C:1E:A8:C6:4C:05:4D:20:EC:88:DB:29:D4:7B:F9:12:5D:CE:EA:1A Signature Algorithm: sha1WithRSAEncryption 56:2f:79:e5:12:91:f5:19:a7:d1:32:28:fd:e3:9d:8f:e1:3c: bb:a3:a5:f2:55:8a:03:ad:2c:1d:18:82:e1:7f:19:75:d9:47: 5b:e7:7c:e4:a5:e0:eb:dc:7e:24:a3:7d:99:1a:cf:39:ba:a5: b4:b8:45:68:83:cf:70:ad:56:f2:34:73:65:fc:6c:b0:53:9a: 79:04:f7:3e:7e:4b:22:1b:e7:76:23:20:bc:9c:05:a2:5d:01: d2:f0:09:49:17:b2:61:74:1a:5b:f4:e0:fd:ce:11:ba:13:4a: e6:07:11:7d:30:e2:11:87:ee:33:1a:68:de:67:f4:ac:b5:58: 1a:ac:cf:7a:2d:fd:c3:44:5b:4b:cd:6c:ff:f6:49:b4:55:4a: 09:a0:92:2d:57:3b:69:85:54:3e:e9:ec:ef:b2:a5:7a:29:75: 2b:f8:eb:4b:d4:cf:68:ee:3e:c8:63:7e:12:eb:e4:2f:63:a3: a7:c8:0f:e9:39:ff:5c:29:65:7f:25:f0:42:bf:07:ba:06:b8: 5e:d6:56:ba:f8:67:56:1b:42:aa:b3:04:d8:6e:88:10:a5:70: b5:81:04:a4:90:a3:f0:83:4d:0c:6b:12:5d:a4:4c:83:5a:ff: a8:7a:86:61:ff:0f:4c:e5:0f:17:d1:64:3c:bd:d9:22:7e:b7: fa:9b:83:ba -----BEGIN CERTIFICATE----- MIIDtDCCApygAwIBAgIBATANBgkqhkiG9w0BAQUFADBqMQswCQYDVQQGEwJVUzET MBEGA1UECgwKUHJvbWV0aGV1czEpMCcGA1UECwwgUHJvbWV0aGV1cyBDZXJ0aWZp Y2F0ZSBBdXRob3JpdHkxGzAZBgNVBAMMElByb21ldGhldXMgUm9vdCBDQTAgFw0x OTA0MDUwNzU1MDBaGA8yMDU5MDMyNjA3NTUwMFowajELMAkGA1UEBhMCVVMxEzAR BgNVBAoMClByb21ldGhldXMxKTAnBgNVBAsMIFByb21ldGhldXMgQ2VydGlmaWNh dGUgQXV0aG9yaXR5MRswGQYDVQQDDBJQcm9tZXRoZXVzIFJvb3QgQ0EwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/ueKrX2Ei4U7N7tqwJi67sH4czhC+ Fik1DAwdkwEpKvb5wm5cEETK+NytegZkD4oYrbKilEnJuoxFlHzZ4BFF2BZ5oiCf jGNgcipb+WaArIVnAVrrkcHSiIeeTBjJ8vB6GMDmqyx43l+yIk6UnPXN5uIzMOkg EKahdetZq0Wp9z5UQK4FJb50xTr9r3MWYEV8SuAODaEVf5ofwqcEre+z5PYALE4L BJBJ7tPbphLEkQsyTxGEx8SK71FmerAgL8uVjZZXYGZe+U9alJxxrevKcD5iBsI6 Kfiehq/aB3j4Ma9CSEmeSt8bJx9ENYFt+nrFago1I8fE1f7JnmHJMM0fAgMBAAGj YzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQ8 HqjGTAVNIOyI2ynUe/kSXc7qGjAfBgNVHSMEGDAWgBQ8HqjGTAVNIOyI2ynUe/kS Xc7qGjANBgkqhkiG9w0BAQUFAAOCAQEAVi955RKR9Rmn0TIo/eOdj+E8u6Ol8lWK A60sHRiC4X8ZddlHW+d85KXg69x+JKN9mRrPObqltLhFaIPPcK1W8jRzZfxssFOa eQT3Pn5LIhvndiMgvJwFol0B0vAJSReyYXQaW/Tg/c4RuhNK5gcRfTDiEYfuMxpo 3mf0rLVYGqzPei39w0RbS81s//ZJtFVKCaCSLVc7aYVUPuns77Kleil1K/jrS9TP aO4+yGN+EuvkL2Ojp8gP6Tn/XCllfyXwQr8Huga4XtZWuvhnVhtCqrME2G6IEKVw tYEEpJCj8INNDGsSXaRMg1r/qHqGYf8PTOUPF9FkPL3ZIn63+puDug== -----END CERTIFICATE----- tls_config_noAuth.requireanyclientcert.good.yml000066400000000000000000000002261415441071500356600ustar00rootroot00000000000000golang-github-prometheus-exporter-toolkit-0.7.1/web/testdatatls_server_config: cert_file: "server.crt" key_file: "server.key" client_auth_type: "RequireAnyClientCert" client_ca_file: "tls-ca-chain.pem" web_config_auth_clientCAs_invalid.bad.yml000066400000000000000000000001461415441071500343300ustar00rootroot00000000000000golang-github-prometheus-exporter-toolkit-0.7.1/web/testdatatls_server_config : cert_file : "server.crt" key_file : "server.key" client_ca_file : "somefile"web_config_auth_clientCAs_missing.bad.yml000066400000000000000000000001721415441071500343520ustar00rootroot00000000000000golang-github-prometheus-exporter-toolkit-0.7.1/web/testdatatls_server_config : cert_file : "server.crt" key_file : "server.key" client_auth_type : "RequireAndVerifyClientCert"web_config_auth_user_list_invalid.bad.yml000066400000000000000000000001471415441071500344750ustar00rootroot00000000000000golang-github-prometheus-exporter-toolkit-0.7.1/web/testdatatls_server_config : cert_file : "server.crt" key_file : "server.key" basic_auth_users: john: doe golang-github-prometheus-exporter-toolkit-0.7.1/web/testdata/web_config_empty.yml000066400000000000000000000000001415441071500304110ustar00rootroot00000000000000golang-github-prometheus-exporter-toolkit-0.7.1/web/testdata/web_config_headers.good.yml000066400000000000000000000003751415441071500316340ustar00rootroot00000000000000http_server_config: headers: X-Frame-Options: deny Strict-Transport-Security: max-age=31536000; includeSubDomains X-Content-Type-Options: nosniff X-XSS-Protection: 1 Content-Security-Policy: "default-src 'self' *.test.example.net" web_config_headers_content_type_options.bad.yml000066400000000000000000000001011415441071500357040ustar00rootroot00000000000000golang-github-prometheus-exporter-toolkit-0.7.1/web/testdatahttp_server_config: headers: X-Content-Type-Options: sniff golang-github-prometheus-exporter-toolkit-0.7.1/web/testdata/web_config_headers_extra_header.bad.yml000066400000000000000000000000651415441071500341410ustar00rootroot00000000000000http_server_config: headers: Content-Type: foo web_config_headers_frame_options.bad.yml000066400000000000000000000000701415441071500342700ustar00rootroot00000000000000golang-github-prometheus-exporter-toolkit-0.7.1/web/testdatahttp_server_config: headers: X-Frame-Options: foo golang-github-prometheus-exporter-toolkit-0.7.1/web/testdata/web_config_junk.yml000066400000000000000000000006441415441071500302400ustar00rootroot00000000000000hWkNKCp3fvIx3jKnsaBI TuEjdwNS8A2vYdFbiKqr ay3RiOtykgt4m6m3KOol ZreGpJRGmpDSVV9cioiF r7kDOHhHU2frvv0nLcY2 uQMQM4XgqFkCG6gFAIJZ g99tTkrZhN9b6pkJ6J2y rzdt729HrA2RblDGYfjs MW7GxrBdlCnliYJGPhfr g9kaXxMXcDwsw0C0rv0u 637ZmfRGElb6VBVOtgqn RG0MRezjLYCJQBMUdRDE RzO4VicAzj7asVZAT3oo nPw267UONk7h7KBYRgch Alj38foWqjV3heXXdahm TrMzMgl6JIQ1x4OZB5i4 qlrXFJoeV6Pr77nuiEh9 3yE5vMnnKHm2nImEfzMG bI01UDObHRSaoJLC0vTD G9tlcKU883NkQ6nsxJ8Y golang-github-prometheus-exporter-toolkit-0.7.1/web/testdata/web_config_junk_key.yml000066400000000000000000000000571415441071500311060ustar00rootroot00000000000000tls_server_config : cert_filse: "server.crt" golang-github-prometheus-exporter-toolkit-0.7.1/web/testdata/web_config_noAuth.bad.yml000066400000000000000000000001601415441071500312450ustar00rootroot00000000000000tls_server_config : cert_file : "server.crt" key_file : "server.key" client_ca_file : "tls-ca-chain.pem" golang-github-prometheus-exporter-toolkit-0.7.1/web/testdata/web_config_noAuth.good.blocking.yml000066400000000000000000000002371415441071500332430ustar00rootroot00000000000000tls_server_config : cert_file : "server.crt" key_file : "server.key" client_auth_type : "RequireAndVerifyClientCert" client_ca_file: "tls-ca-chain.pem"golang-github-prometheus-exporter-toolkit-0.7.1/web/testdata/web_config_noAuth.good.yml000066400000000000000000000002361415441071500314530ustar00rootroot00000000000000tls_server_config : cert_file : "server.crt" key_file : "server.key" client_auth_type : "VerifyClientCertIfGiven" client_ca_file : "tls-ca-chain.pem" golang-github-prometheus-exporter-toolkit-0.7.1/web/testdata/web_config_noAuth_allCiphers.good.yml000066400000000000000000000016111415441071500336170ustar00rootroot00000000000000tls_server_config : cert_file : "server.crt" key_file : "server.key" client_auth_type : "VerifyClientCertIfGiven" client_ca_file : "tls-ca-chain.pem" cipher_suites: - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 - TLS_AES_128_GCM_SHA256 - TLS_AES_256_GCM_SHA384 - TLS_CHACHA20_POLY1305_SHA256 - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA - TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA - TLS_RSA_WITH_3DES_EDE_CBC_SHA - TLS_RSA_WITH_AES_128_CBC_SHA - TLS_RSA_WITH_AES_256_CBC_SHA - TLS_RSA_WITH_AES_128_GCM_SHA256 - TLS_RSA_WITH_AES_256_GCM_SHA384 golang-github-prometheus-exporter-toolkit-0.7.1/web/testdata/web_config_noAuth_allCurves.good.yml000066400000000000000000000003601415441071500334710ustar00rootroot00000000000000tls_server_config : cert_file : "server.crt" key_file : "server.key" client_auth_type : "VerifyClientCertIfGiven" client_ca_file : "tls-ca-chain.pem" curve_preferences: - CurveP256 - CurveP384 - CurveP521 - X25519 web_config_noAuth_certPath_empty.bad.yml000066400000000000000000000000761415441071500342440ustar00rootroot00000000000000golang-github-prometheus-exporter-toolkit-0.7.1/web/testdatatls_server_config : cert_file : "" key_file : "server.key"web_config_noAuth_certPath_invalid.bad.yml000066400000000000000000000001061415441071500345260ustar00rootroot00000000000000golang-github-prometheus-exporter-toolkit-0.7.1/web/testdatatls_server_config : cert_file : "somefile" key_file : "server.key"web_config_noAuth_certPath_keyPath_empty.bad.yml000066400000000000000000000001151415441071500357230ustar00rootroot00000000000000golang-github-prometheus-exporter-toolkit-0.7.1/web/testdatatls_server_config : cert_file : "" key_file : "" client_auth_type: "x" web_config_noAuth_certPath_keyPath_invalid.bad.yml000066400000000000000000000001041415441071500362110ustar00rootroot00000000000000golang-github-prometheus-exporter-toolkit-0.7.1/web/testdatatls_server_config : cert_file : "somefile" key_file : "somefile"web_config_noAuth_inventedCiphers.bad.yml000066400000000000000000000003351415441071500344040ustar00rootroot00000000000000golang-github-prometheus-exporter-toolkit-0.7.1/web/testdatatls_server_config : cert_file : "server.crt" key_file : "server.key" client_auth_type : "VerifyClientCertIfGiven" client_ca_file : "tls-ca-chain.pem" cipher_suites: - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA2048 web_config_noAuth_inventedCurves.bad.yml000066400000000000000000000003031415441071500342510ustar00rootroot00000000000000golang-github-prometheus-exporter-toolkit-0.7.1/web/testdatatls_server_config : cert_file : "server.crt" key_file : "server.key" client_auth_type : "VerifyClientCertIfGiven" client_ca_file : "tls-ca-chain.pem" curve_preferences: - CurveP257 golang-github-prometheus-exporter-toolkit-0.7.1/web/testdata/web_config_noAuth_keyPath_empty.bad.yml000066400000000000000000000000761415441071500341560ustar00rootroot00000000000000tls_server_config : cert_file : "server.crt" key_file : ""web_config_noAuth_keyPath_invalid.bad.yml000066400000000000000000000001071415441071500343620ustar00rootroot00000000000000golang-github-prometheus-exporter-toolkit-0.7.1/web/testdatatls_server_config : cert_file : "server.cert" key_file : "somefile"golang-github-prometheus-exporter-toolkit-0.7.1/web/testdata/web_config_noAuth_noHTTP2.good.yml000066400000000000000000000004121415441071500327250ustar00rootroot00000000000000tls_server_config : cert_file : "server.crt" key_file : "server.key" client_auth_type : "VerifyClientCertIfGiven" client_ca_file : "tls-ca-chain.pem" cipher_suites: - TLS_RSA_WITH_AES_128_CBC_SHA max_version: TLS12 http_server_config: http2: false golang-github-prometheus-exporter-toolkit-0.7.1/web/testdata/web_config_noAuth_noHTTP2Cipher.bad.yml000066400000000000000000000003471415441071500336650ustar00rootroot00000000000000tls_server_config : cert_file : "server.crt" key_file : "server.key" client_auth_type : "VerifyClientCertIfGiven" client_ca_file : "tls-ca-chain.pem" cipher_suites: - TLS_RSA_WITH_AES_128_CBC_SHA max_version: TLS12 golang-github-prometheus-exporter-toolkit-0.7.1/web/testdata/web_config_noAuth_someCiphers.good.yml000066400000000000000000000004551415441071500340170ustar00rootroot00000000000000tls_server_config : cert_file : "server.crt" key_file : "server.key" client_auth_type : "VerifyClientCertIfGiven" client_ca_file : "tls-ca-chain.pem" cipher_suites: - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 min_version: TLS12 max_version: TLS12 web_config_noAuth_someCiphers_noOrder.good.yml000066400000000000000000000005221415441071500354230ustar00rootroot00000000000000golang-github-prometheus-exporter-toolkit-0.7.1/web/testdatatls_server_config : cert_file : "server.crt" key_file : "server.key" client_auth_type : "VerifyClientCertIfGiven" client_ca_file : "tls-ca-chain.pem" cipher_suites: - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 prefer_server_cipher_suites: false min_version: TLS12 max_version: TLS12 golang-github-prometheus-exporter-toolkit-0.7.1/web/testdata/web_config_noAuth_someCurves.good.yml000066400000000000000000000003261415441071500336660ustar00rootroot00000000000000tls_server_config : cert_file : "server.crt" key_file : "server.key" client_auth_type : "VerifyClientCertIfGiven" client_ca_file : "tls-ca-chain.pem" min_version: TLS13 curve_preferences: - CurveP521 web_config_noAuth_wrongTLSVersion.bad.yml000066400000000000000000000002641415441071500343400ustar00rootroot00000000000000golang-github-prometheus-exporter-toolkit-0.7.1/web/testdatatls_server_config : cert_file : "server.crt" key_file : "server.key" client_auth_type : "VerifyClientCertIfGiven" client_ca_file : "tls-ca-chain.pem" min_version: TLS111 golang-github-prometheus-exporter-toolkit-0.7.1/web/testdata/web_config_users.good.yml000066400000000000000000000005601415441071500313560ustar00rootroot00000000000000tls_server_config : cert_file : "server.crt" key_file : "server.key" basic_auth_users: alice: $2y$12$1DpfPeqF9HzHJt.EWswy1exHluGfbhnn3yXhR7Xes6m3WJqFg0Wby bob: $2y$18$4VeFDzXIoPHKnKTU3O3GH.N.vZu06CVqczYZ8WvfzrddFU6tGqjR. carol: $2y$10$qRTBuFoULoYNA7AQ/F3ck.trZBPyjV64.oA4ZsSBCIWvXuvQlQTuu dave: $2y$10$2UXri9cIDdgeKjBo4Rlpx.U3ZLDV8X1IxKmsfOvhcM5oXQt/mLmXq golang-github-prometheus-exporter-toolkit-0.7.1/web/testdata/web_config_users_noTLS.good.yml000066400000000000000000000004471415441071500324410ustar00rootroot00000000000000basic_auth_users: alice: $2y$12$1DpfPeqF9HzHJt.EWswy1exHluGfbhnn3yXhR7Xes6m3WJqFg0Wby bob: $2y$18$4VeFDzXIoPHKnKTU3O3GH.N.vZu06CVqczYZ8WvfzrddFU6tGqjR. carol: $2y$10$qRTBuFoULoYNA7AQ/F3ck.trZBPyjV64.oA4ZsSBCIWvXuvQlQTuu dave: $2y$10$2UXri9cIDdgeKjBo4Rlpx.U3ZLDV8X1IxKmsfOvhcM5oXQt/mLmXq golang-github-prometheus-exporter-toolkit-0.7.1/web/tls_config.go000066400000000000000000000226561415441071500252400ustar00rootroot00000000000000// Copyright 2019 The Prometheus Authors // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package web import ( "crypto/tls" "crypto/x509" "fmt" "io/ioutil" "net" "net/http" "path/filepath" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/pkg/errors" config_util "github.com/prometheus/common/config" "gopkg.in/yaml.v2" ) var ( errNoTLSConfig = errors.New("TLS config is not present") ) type Config struct { TLSConfig TLSStruct `yaml:"tls_server_config"` HTTPConfig HTTPStruct `yaml:"http_server_config"` Users map[string]config_util.Secret `yaml:"basic_auth_users"` } type TLSStruct struct { TLSCertPath string `yaml:"cert_file"` TLSKeyPath string `yaml:"key_file"` ClientAuth string `yaml:"client_auth_type"` ClientCAs string `yaml:"client_ca_file"` CipherSuites []cipher `yaml:"cipher_suites"` CurvePreferences []curve `yaml:"curve_preferences"` MinVersion tlsVersion `yaml:"min_version"` MaxVersion tlsVersion `yaml:"max_version"` PreferServerCipherSuites bool `yaml:"prefer_server_cipher_suites"` } // SetDirectory joins any relative file paths with dir. func (t *TLSStruct) SetDirectory(dir string) { t.TLSCertPath = config_util.JoinDir(dir, t.TLSCertPath) t.TLSKeyPath = config_util.JoinDir(dir, t.TLSKeyPath) t.ClientCAs = config_util.JoinDir(dir, t.ClientCAs) } type HTTPStruct struct { HTTP2 bool `yaml:"http2"` Header map[string]string `yaml:"headers,omitempty"` } func getConfig(configPath string) (*Config, error) { content, err := ioutil.ReadFile(configPath) if err != nil { return nil, err } c := &Config{ TLSConfig: TLSStruct{ MinVersion: tls.VersionTLS12, MaxVersion: tls.VersionTLS13, PreferServerCipherSuites: true, }, HTTPConfig: HTTPStruct{HTTP2: true}, } err = yaml.UnmarshalStrict(content, c) if err == nil { err = validateHeaderConfig(c.HTTPConfig.Header) } c.TLSConfig.SetDirectory(filepath.Dir(configPath)) return c, err } func getTLSConfig(configPath string) (*tls.Config, error) { c, err := getConfig(configPath) if err != nil { return nil, err } return ConfigToTLSConfig(&c.TLSConfig) } // ConfigToTLSConfig generates the golang tls.Config from the TLSStruct config. func ConfigToTLSConfig(c *TLSStruct) (*tls.Config, error) { if c.TLSCertPath == "" && c.TLSKeyPath == "" && c.ClientAuth == "" && c.ClientCAs == "" { return nil, errNoTLSConfig } if c.TLSCertPath == "" { return nil, errors.New("missing cert_file") } if c.TLSKeyPath == "" { return nil, errors.New("missing key_file") } loadCert := func() (*tls.Certificate, error) { cert, err := tls.LoadX509KeyPair(c.TLSCertPath, c.TLSKeyPath) if err != nil { return nil, errors.Wrap(err, "failed to load X509KeyPair") } return &cert, nil } // Confirm that certificate and key paths are valid. if _, err := loadCert(); err != nil { return nil, err } cfg := &tls.Config{ MinVersion: (uint16)(c.MinVersion), MaxVersion: (uint16)(c.MaxVersion), PreferServerCipherSuites: c.PreferServerCipherSuites, } cfg.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) { return loadCert() } var cf []uint16 for _, c := range c.CipherSuites { cf = append(cf, (uint16)(c)) } if len(cf) > 0 { cfg.CipherSuites = cf } var cp []tls.CurveID for _, c := range c.CurvePreferences { cp = append(cp, (tls.CurveID)(c)) } if len(cp) > 0 { cfg.CurvePreferences = cp } if c.ClientCAs != "" { clientCAPool := x509.NewCertPool() clientCAFile, err := ioutil.ReadFile(c.ClientCAs) if err != nil { return nil, err } clientCAPool.AppendCertsFromPEM(clientCAFile) cfg.ClientCAs = clientCAPool } switch c.ClientAuth { case "RequestClientCert": cfg.ClientAuth = tls.RequestClientCert case "RequireAnyClientCert", "RequireClientCert": // Preserved for backwards compatibility. cfg.ClientAuth = tls.RequireAnyClientCert case "VerifyClientCertIfGiven": cfg.ClientAuth = tls.VerifyClientCertIfGiven case "RequireAndVerifyClientCert": cfg.ClientAuth = tls.RequireAndVerifyClientCert case "", "NoClientCert": cfg.ClientAuth = tls.NoClientCert default: return nil, errors.New("Invalid ClientAuth: " + c.ClientAuth) } if c.ClientCAs != "" && cfg.ClientAuth == tls.NoClientCert { return nil, errors.New("Client CA's have been configured without a Client Auth Policy") } return cfg, nil } // ListenAndServe starts the server on the given address. Based on the file // tlsConfigPath, TLS or basic auth could be enabled. func ListenAndServe(server *http.Server, tlsConfigPath string, logger log.Logger) error { listener, err := net.Listen("tcp", server.Addr) if err != nil { return err } defer listener.Close() return Serve(listener, server, tlsConfigPath, logger) } // Server starts the server on the given listener. Based on the file // tlsConfigPath, TLS or basic auth could be enabled. func Serve(l net.Listener, server *http.Server, tlsConfigPath string, logger log.Logger) error { if tlsConfigPath == "" { level.Info(logger).Log("msg", "TLS is disabled.", "http2", false) return server.Serve(l) } if err := validateUsers(tlsConfigPath); err != nil { return err } // Setup basic authentication. var handler http.Handler = http.DefaultServeMux if server.Handler != nil { handler = server.Handler } c, err := getConfig(tlsConfigPath) if err != nil { return err } server.Handler = &webHandler{ tlsConfigPath: tlsConfigPath, logger: logger, handler: handler, cache: newCache(), } config, err := ConfigToTLSConfig(&c.TLSConfig) switch err { case nil: if !c.HTTPConfig.HTTP2 { server.TLSNextProto = make(map[string]func(*http.Server, *tls.Conn, http.Handler)) } // Valid TLS config. level.Info(logger).Log("msg", "TLS is enabled.", "http2", c.HTTPConfig.HTTP2) case errNoTLSConfig: // No TLS config, back to plain HTTP. level.Info(logger).Log("msg", "TLS is disabled.", "http2", false) return server.Serve(l) default: // Invalid TLS config. return err } server.TLSConfig = config // Set the GetConfigForClient method of the HTTPS server so that the config // and certs are reloaded on new connections. server.TLSConfig.GetConfigForClient = func(*tls.ClientHelloInfo) (*tls.Config, error) { config, err := getTLSConfig(tlsConfigPath) if err != nil { return nil, err } config.NextProtos = server.TLSConfig.NextProtos return config, nil } return server.ServeTLS(l, "", "") } // Validate configuration file by reading the configuration and the certificates. func Validate(tlsConfigPath string) error { if tlsConfigPath == "" { return nil } if err := validateUsers(tlsConfigPath); err != nil { return err } c, err := getConfig(tlsConfigPath) if err != nil { return err } _, err = ConfigToTLSConfig(&c.TLSConfig) if err == errNoTLSConfig { return nil } return err } type cipher uint16 func (c *cipher) UnmarshalYAML(unmarshal func(interface{}) error) error { var s string err := unmarshal((*string)(&s)) if err != nil { return err } for _, cs := range tls.CipherSuites() { if cs.Name == s { *c = (cipher)(cs.ID) return nil } } return errors.New("unknown cipher: " + s) } func (c cipher) MarshalYAML() (interface{}, error) { return tls.CipherSuiteName((uint16)(c)), nil } type curve tls.CurveID var curves = map[string]curve{ "CurveP256": (curve)(tls.CurveP256), "CurveP384": (curve)(tls.CurveP384), "CurveP521": (curve)(tls.CurveP521), "X25519": (curve)(tls.X25519), } func (c *curve) UnmarshalYAML(unmarshal func(interface{}) error) error { var s string err := unmarshal((*string)(&s)) if err != nil { return err } if curveid, ok := curves[s]; ok { *c = curveid return nil } return errors.New("unknown curve: " + s) } func (c *curve) MarshalYAML() (interface{}, error) { for s, curveid := range curves { if *c == curveid { return s, nil } } return fmt.Sprintf("%v", c), nil } type tlsVersion uint16 var tlsVersions = map[string]tlsVersion{ "TLS13": (tlsVersion)(tls.VersionTLS13), "TLS12": (tlsVersion)(tls.VersionTLS12), "TLS11": (tlsVersion)(tls.VersionTLS11), "TLS10": (tlsVersion)(tls.VersionTLS10), } func (tv *tlsVersion) UnmarshalYAML(unmarshal func(interface{}) error) error { var s string err := unmarshal((*string)(&s)) if err != nil { return err } if v, ok := tlsVersions[s]; ok { *tv = v return nil } return errors.New("unknown TLS version: " + s) } func (tv *tlsVersion) MarshalYAML() (interface{}, error) { for s, v := range tlsVersions { if *tv == v { return s, nil } } return fmt.Sprintf("%v", tv), nil } // Listen starts the server on the given address. Based on the file // tlsConfigPath, TLS or basic auth could be enabled. // // Deprecated: Use ListenAndServe instead. func Listen(server *http.Server, tlsConfigPath string, logger log.Logger) error { return ListenAndServe(server, tlsConfigPath, logger) } golang-github-prometheus-exporter-toolkit-0.7.1/web/tls_config_test.go000066400000000000000000000441251415441071500262720ustar00rootroot00000000000000// Copyright 2019 The Prometheus Authors // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // +build go1.14 package web import ( "crypto/tls" "crypto/x509" "errors" "fmt" "io/ioutil" "net" "net/http" "regexp" "sync" "testing" "time" ) var ( port = getPort() testlogger = &testLogger{} ErrorMap = map[string]*regexp.Regexp{ "HTTP Response to HTTPS": regexp.MustCompile(`server gave HTTP response to HTTPS client`), "No such file": regexp.MustCompile(`no such file`), "Invalid argument": regexp.MustCompile(`invalid argument`), "YAML error": regexp.MustCompile(`yaml`), "Invalid ClientAuth": regexp.MustCompile(`invalid ClientAuth`), "TLS handshake": regexp.MustCompile(`tls`), "HTTP Request to HTTPS server": regexp.MustCompile(`HTTP`), "Invalid CertPath": regexp.MustCompile(`missing cert_file`), "Invalid KeyPath": regexp.MustCompile(`missing key_file`), "ClientCA set without policy": regexp.MustCompile(`Client CA's have been configured without a Client Auth Policy`), "Bad password": regexp.MustCompile(`hashedSecret too short to be a bcrypted password`), "Unauthorized": regexp.MustCompile(`Unauthorized`), "Forbidden": regexp.MustCompile(`Forbidden`), "Handshake failure": regexp.MustCompile(`handshake failure`), "Unknown cipher": regexp.MustCompile(`unknown cipher`), "Unknown curve": regexp.MustCompile(`unknown curve`), "Unknown TLS version": regexp.MustCompile(`unknown TLS version`), "No HTTP2 cipher": regexp.MustCompile(`TLSConfig.CipherSuites is missing an HTTP/2-required`), "Incompatible TLS version": regexp.MustCompile(`protocol version not supported`), "Bad certificate": regexp.MustCompile(`bad certificate`), "Invalid value": regexp.MustCompile(`invalid value for`), "Invalid header": regexp.MustCompile(`HTTP header ".*" can not be configured`), } ) type testLogger struct{} func (t *testLogger) Log(keyvals ...interface{}) error { return nil } func getPort() string { listener, err := net.Listen("tcp", ":0") if err != nil { panic(err) } defer listener.Close() p := listener.Addr().(*net.TCPAddr).Port return fmt.Sprintf(":%v", p) } type TestInputs struct { Name string Server func() *http.Server YAMLConfigPath string ExpectedError *regexp.Regexp UseTLSClient bool ClientMaxTLSVersion uint16 CipherSuites []uint16 ActualCipher uint16 CurvePreferences []tls.CurveID Username string Password string } func TestYAMLFiles(t *testing.T) { testTables := []*TestInputs{ { Name: `path to config yml invalid`, YAMLConfigPath: "somefile", ExpectedError: ErrorMap["No such file"], }, { Name: `empty config yml`, YAMLConfigPath: "testdata/web_config_empty.yml", ExpectedError: nil, }, { Name: `invalid config yml (invalid structure)`, YAMLConfigPath: "testdata/web_config_junk.yml", ExpectedError: ErrorMap["YAML error"], }, { Name: `invalid config yml (invalid key)`, YAMLConfigPath: "testdata/web_config_junk_key.yml", ExpectedError: ErrorMap["YAML error"], }, { Name: `invalid config yml (cert path empty)`, YAMLConfigPath: "testdata/web_config_noAuth_certPath_empty.bad.yml", ExpectedError: ErrorMap["Invalid CertPath"], }, { Name: `invalid config yml (key path empty)`, YAMLConfigPath: "testdata/web_config_noAuth_keyPath_empty.bad.yml", ExpectedError: ErrorMap["Invalid KeyPath"], }, { Name: `invalid config yml (cert path and key path empty)`, YAMLConfigPath: "testdata/web_config_noAuth_certPath_keyPath_empty.bad.yml", ExpectedError: ErrorMap["Invalid CertPath"], }, { Name: `invalid config yml (cert path invalid)`, YAMLConfigPath: "testdata/web_config_noAuth_certPath_invalid.bad.yml", ExpectedError: ErrorMap["No such file"], }, { Name: `invalid config yml (key path invalid)`, YAMLConfigPath: "testdata/web_config_noAuth_keyPath_invalid.bad.yml", ExpectedError: ErrorMap["No such file"], }, { Name: `invalid config yml (cert path and key path invalid)`, YAMLConfigPath: "testdata/web_config_noAuth_certPath_keyPath_invalid.bad.yml", ExpectedError: ErrorMap["No such file"], }, { Name: `invalid config yml (invalid ClientAuth)`, YAMLConfigPath: "testdata/web_config_noAuth.bad.yml", ExpectedError: ErrorMap["ClientCA set without policy"], }, { Name: `invalid config yml (invalid ClientCAs filepath)`, YAMLConfigPath: "testdata/web_config_auth_clientCAs_invalid.bad.yml", ExpectedError: ErrorMap["No such file"], }, { Name: `invalid config yml (invalid user list)`, YAMLConfigPath: "testdata/web_config_auth_user_list_invalid.bad.yml", ExpectedError: ErrorMap["Bad password"], }, { Name: `invalid config yml (bad cipher)`, YAMLConfigPath: "testdata/web_config_noAuth_inventedCiphers.bad.yml", ExpectedError: ErrorMap["Unknown cipher"], }, { Name: `invalid config yml (bad curves)`, YAMLConfigPath: "testdata/web_config_noAuth_inventedCurves.bad.yml", ExpectedError: ErrorMap["Unknown curve"], }, { Name: `invalid config yml (bad TLS version)`, YAMLConfigPath: "testdata/web_config_noAuth_wrongTLSVersion.bad.yml", ExpectedError: ErrorMap["Unknown TLS version"], }, } for _, testInputs := range testTables { t.Run("run/"+testInputs.Name, testInputs.Test) t.Run("validate/"+testInputs.Name, testInputs.TestValidate) } } func TestServerBehaviour(t *testing.T) { testTables := []*TestInputs{ { Name: `empty string YAMLConfigPath and default client`, YAMLConfigPath: "", ExpectedError: nil, }, { Name: `empty string YAMLConfigPath and TLS client`, YAMLConfigPath: "", UseTLSClient: true, ExpectedError: ErrorMap["HTTP Response to HTTPS"], }, { Name: `valid tls config yml and default client`, YAMLConfigPath: "testdata/web_config_noAuth.good.yml", ExpectedError: ErrorMap["HTTP Request to HTTPS server"], }, { Name: `valid tls config yml and tls client`, YAMLConfigPath: "testdata/web_config_noAuth.good.yml", UseTLSClient: true, ExpectedError: nil, }, { Name: `valid tls config yml with TLS 1.1 client`, YAMLConfigPath: "testdata/web_config_noAuth.good.yml", UseTLSClient: true, ClientMaxTLSVersion: tls.VersionTLS11, ExpectedError: ErrorMap["Incompatible TLS version"], }, { Name: `valid tls config yml with all ciphers`, YAMLConfigPath: "testdata/web_config_noAuth_allCiphers.good.yml", UseTLSClient: true, ExpectedError: nil, }, { Name: `valid tls config yml with some ciphers`, YAMLConfigPath: "testdata/web_config_noAuth_someCiphers.good.yml", UseTLSClient: true, CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, ExpectedError: nil, }, { Name: `valid tls config yml with no common cipher`, YAMLConfigPath: "testdata/web_config_noAuth_someCiphers.good.yml", UseTLSClient: true, CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}, ExpectedError: ErrorMap["Handshake failure"], }, { Name: `valid tls config yml with multiple client ciphers`, YAMLConfigPath: "testdata/web_config_noAuth_someCiphers.good.yml", UseTLSClient: true, CipherSuites: []uint16{ tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, }, ActualCipher: tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, ExpectedError: nil, }, { Name: `valid tls config yml with multiple client ciphers, client chooses cipher`, YAMLConfigPath: "testdata/web_config_noAuth_someCiphers_noOrder.good.yml", UseTLSClient: true, CipherSuites: []uint16{ tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, }, ActualCipher: tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, ExpectedError: nil, }, { Name: `valid tls config yml with all curves`, YAMLConfigPath: "testdata/web_config_noAuth_allCurves.good.yml", UseTLSClient: true, ExpectedError: nil, }, { Name: `valid tls config yml with some curves`, YAMLConfigPath: "testdata/web_config_noAuth_someCurves.good.yml", UseTLSClient: true, CurvePreferences: []tls.CurveID{tls.CurveP521}, ExpectedError: nil, }, { Name: `valid tls config yml with no common curves`, YAMLConfigPath: "testdata/web_config_noAuth_someCurves.good.yml", UseTLSClient: true, CurvePreferences: []tls.CurveID{tls.CurveP384}, ExpectedError: ErrorMap["Handshake failure"], }, { Name: `valid tls config yml with non-http2 ciphers`, YAMLConfigPath: "testdata/web_config_noAuth_noHTTP2.good.yml", UseTLSClient: true, ExpectedError: nil, }, { Name: `valid tls config yml with non-http2 ciphers but http2 enabled`, YAMLConfigPath: "testdata/web_config_noAuth_noHTTP2Cipher.bad.yml", UseTLSClient: true, ExpectedError: ErrorMap["No HTTP2 cipher"], }, { Name: `valid tls config yml and tls client with RequireAnyClientCert`, YAMLConfigPath: "testdata/tls_config_noAuth.requireanyclientcert.good.yml", UseTLSClient: true, ExpectedError: ErrorMap["Bad certificate"], }, { Name: `valid headers config`, YAMLConfigPath: "testdata/web_config_headers.good.yml", }, { Name: `invalid X-Content-Type-Options headers config`, YAMLConfigPath: "testdata/web_config_headers_content_type_options.bad.yml", ExpectedError: ErrorMap["Invalid value"], }, { Name: `invalid X-Frame-Options headers config`, YAMLConfigPath: "testdata/web_config_headers_frame_options.bad.yml", ExpectedError: ErrorMap["Invalid value"], }, { Name: `HTTP header that can not be overriden`, YAMLConfigPath: "testdata/web_config_headers_extra_header.bad.yml", ExpectedError: ErrorMap["Invalid header"], }, } for _, testInputs := range testTables { t.Run(testInputs.Name, testInputs.Test) } } func TestConfigReloading(t *testing.T) { errorChannel := make(chan error, 1) var once sync.Once recordConnectionError := func(err error) { once.Do(func() { errorChannel <- err }) } defer func() { if recover() != nil { recordConnectionError(errors.New("Panic in test function")) } }() goodYAMLPath := "testdata/web_config_noAuth.good.yml" badYAMLPath := "testdata/web_config_noAuth.good.blocking.yml" server := &http.Server{ Addr: port, Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello World!")) }), } defer func() { server.Close() }() go func() { defer func() { if recover() != nil { recordConnectionError(errors.New("Panic starting server")) } }() err := Listen(server, badYAMLPath, testlogger) recordConnectionError(err) }() client := getTLSClient() TestClientConnection := func() error { time.Sleep(250 * time.Millisecond) r, err := client.Get("https://localhost" + port) if err != nil { return err } body, err := ioutil.ReadAll(r.Body) if err != nil { return err } if string(body) != "Hello World!" { return errors.New(string(body)) } return nil } err := TestClientConnection() if err == nil { recordConnectionError(errors.New("connection accepted but should have failed")) } else { swapFileContents(goodYAMLPath, badYAMLPath) defer swapFileContents(goodYAMLPath, badYAMLPath) err = TestClientConnection() if err != nil { recordConnectionError(errors.New("connection failed but should have been accepted")) } else { recordConnectionError(nil) } } err = <-errorChannel if err != nil { t.Errorf(" *** Failed test: %s *** Returned error: %v", "TestConfigReloading", err) } } func (test *TestInputs) Test(t *testing.T) { errorChannel := make(chan error, 1) var once sync.Once recordConnectionError := func(err error) { once.Do(func() { errorChannel <- err }) } defer func() { if recover() != nil { recordConnectionError(errors.New("Panic in test function")) } }() server := &http.Server{ Addr: port, Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello World!")) }), } t.Cleanup(func() { server.Close() }) go func() { defer func() { if recover() != nil { recordConnectionError(errors.New("Panic starting server")) } }() err := ListenAndServe(server, test.YAMLConfigPath, testlogger) recordConnectionError(err) }() ClientConnection := func() (*http.Response, error) { var client *http.Client var proto string if test.UseTLSClient { client = getTLSClient() t := client.Transport.(*http.Transport) t.TLSClientConfig.MaxVersion = test.ClientMaxTLSVersion if len(test.CipherSuites) > 0 { t.TLSClientConfig.CipherSuites = test.CipherSuites } if len(test.CurvePreferences) > 0 { t.TLSClientConfig.CurvePreferences = test.CurvePreferences } proto = "https" } else { client = http.DefaultClient proto = "http" } req, err := http.NewRequest("GET", proto+"://localhost"+port, nil) if err != nil { t.Error(err) } if test.Username != "" { req.SetBasicAuth(test.Username, test.Password) } return client.Do(req) } go func() { time.Sleep(250 * time.Millisecond) r, err := ClientConnection() if err != nil { recordConnectionError(err) return } if test.ActualCipher != 0 { if r.TLS.CipherSuite != test.ActualCipher { recordConnectionError( fmt.Errorf("bad cipher suite selected. Expected: %s, got: %s", tls.CipherSuiteName(r.TLS.CipherSuite), tls.CipherSuiteName(test.ActualCipher), ), ) } } body, err := ioutil.ReadAll(r.Body) if err != nil { recordConnectionError(err) return } if string(body) != "Hello World!" { recordConnectionError(errors.New(string(body))) return } recordConnectionError(nil) }() err := <-errorChannel if test.isCorrectError(err) == false { if test.ExpectedError == nil { t.Logf("Expected no error, got error: %v", err) } else { t.Logf("Expected error matching regular expression: %v", test.ExpectedError) t.Logf("Got: %v", err) } t.Fail() } } func (test *TestInputs) TestValidate(t *testing.T) { validationErr := Validate(test.YAMLConfigPath) if test.ExpectedError == nil { if validationErr != nil { t.Errorf("Expected no error, got error: %v", validationErr) } return } if validationErr == nil { t.Errorf("Got no error, expected: %v", test.ExpectedError) return } if !test.ExpectedError.MatchString(validationErr.Error()) { t.Errorf("Expected error %v, got error: %v", test.ExpectedError, validationErr) } } func (test *TestInputs) isCorrectError(returnedError error) bool { switch { case returnedError == nil && test.ExpectedError == nil: case returnedError != nil && test.ExpectedError != nil && test.ExpectedError.MatchString(returnedError.Error()): default: return false } return true } func getTLSClient() *http.Client { cert, err := ioutil.ReadFile("testdata/tls-ca-chain.pem") if err != nil { panic("Unable to start TLS client. Check cert path") } client := &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{ RootCAs: func() *x509.CertPool { caCertPool := x509.NewCertPool() caCertPool.AppendCertsFromPEM(cert) return caCertPool }(), }, }, } return client } func swapFileContents(file1, file2 string) error { content1, err := ioutil.ReadFile(file1) if err != nil { return err } content2, err := ioutil.ReadFile(file2) if err != nil { return err } err = ioutil.WriteFile(file1, content2, 0644) if err != nil { return err } err = ioutil.WriteFile(file2, content1, 0644) if err != nil { return err } return nil } func TestUsers(t *testing.T) { testTables := []*TestInputs{ { Name: `without basic auth`, YAMLConfigPath: "testdata/web_config_users_noTLS.good.yml", ExpectedError: ErrorMap["Unauthorized"], }, { Name: `with correct basic auth`, YAMLConfigPath: "testdata/web_config_users_noTLS.good.yml", Username: "dave", Password: "dave123", ExpectedError: nil, }, { Name: `without basic auth and TLS`, YAMLConfigPath: "testdata/web_config_users.good.yml", UseTLSClient: true, ExpectedError: ErrorMap["Unauthorized"], }, { Name: `with correct basic auth and TLS`, YAMLConfigPath: "testdata/web_config_users.good.yml", UseTLSClient: true, Username: "dave", Password: "dave123", ExpectedError: nil, }, { Name: `with another correct basic auth and TLS`, YAMLConfigPath: "testdata/web_config_users.good.yml", UseTLSClient: true, Username: "carol", Password: "carol123", ExpectedError: nil, }, { Name: `with bad password and TLS`, YAMLConfigPath: "testdata/web_config_users.good.yml", UseTLSClient: true, Username: "dave", Password: "bad", ExpectedError: ErrorMap["Unauthorized"], }, { Name: `with bad username and TLS`, YAMLConfigPath: "testdata/web_config_users.good.yml", UseTLSClient: true, Username: "nonexistent", Password: "nonexistent", ExpectedError: ErrorMap["Unauthorized"], }, } for _, testInputs := range testTables { t.Run(testInputs.Name, testInputs.Test) } } golang-github-prometheus-exporter-toolkit-0.7.1/web/web-config.yml000066400000000000000000000002411415441071500253070ustar00rootroot00000000000000# Minimal TLS configuration example. Additionally, a certificate and a key file # are needed. tls_server_config: cert_file: server.crt key_file: server.key