From 839a429820d85b9edbf83a5270d3b2acb0a76a37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CxHuPo=E2=80=9D?= <7513325+vrocwang@users.noreply.github.com> Date: Sat, 14 Sep 2024 12:00:17 +0800 Subject: [PATCH] fork from prologic/pages-server --- .dockerfiles/entrypoint.sh | 17 + .dockerignore | 6 + .gitea/workflows/build.yml | 21 ++ .gitignore | 10 +- Caddyfile | 47 --- Dockerfile | 66 +++- LICENSE | 215 ++----------- Makefile | 91 +++++- README.md | 91 ++---- README_en.md | 67 ---- caddyfile.go | 246 --------------- docker-stack.yml | 32 ++ gitea/frontmatter.go | 180 +++++++++++ gitea/fs.go | 93 ++++++ gitea/gitea.go | 218 +++++++++++++ go.mod | 132 +------- go.sum | 622 ++----------------------------------- main.go | 68 ++++ pages/40x.gohtml | 15 - pages/50x.gohtml | 15 - pages/buf.go | 19 -- pages/cache_domain.go | 370 ---------------------- pages/cache_owner.go | 111 ------- pages/client.go | 88 ------ pages/cname.go | 98 ------ pages/error.go | 10 - pages/failback.go | 94 ------ pages/fake_resp.go | 53 ---- pages/gitea.go | 85 ----- pages/middle.go | 17 - pages/page.go | 21 -- pages/parser.go | 70 ----- pages/route.go | 59 ---- 33 files changed, 865 insertions(+), 2482 deletions(-) create mode 100644 .dockerfiles/entrypoint.sh create mode 100644 .dockerignore create mode 100644 .gitea/workflows/build.yml delete mode 100644 Caddyfile delete mode 100644 README_en.md delete mode 100644 caddyfile.go create mode 100644 docker-stack.yml create mode 100644 gitea/frontmatter.go create mode 100644 gitea/fs.go create mode 100644 gitea/gitea.go create mode 100644 main.go delete mode 100644 pages/40x.gohtml delete mode 100644 pages/50x.gohtml delete mode 100644 pages/buf.go delete mode 100644 pages/cache_domain.go delete mode 100644 pages/cache_owner.go delete mode 100644 pages/client.go delete mode 100644 pages/cname.go delete mode 100644 pages/error.go delete mode 100644 pages/failback.go delete mode 100644 pages/fake_resp.go delete mode 100644 pages/gitea.go delete mode 100644 pages/middle.go delete mode 100644 pages/page.go delete mode 100644 pages/parser.go delete mode 100644 pages/route.go diff --git a/.dockerfiles/entrypoint.sh b/.dockerfiles/entrypoint.sh new file mode 100644 index 0000000..3b35edc --- /dev/null +++ b/.dockerfiles/entrypoint.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +set -e + +if [ "$(id -u)" -eq 0 ]; then + [ -n "${PUID}" ] && usermod -u "${PUID}" nobody + [ -n "${PGID}" ] && groupmod -g "${PGID}" nobody +fi + +printf "Configuring application...\n" + +if [ "$(id -u)" -eq 0 ]; then + printf "Switching UID=%s and GID=%s\n" "$(id -u nobody)" "$(id -g nobody)" + exec su-exec nobody:nobody "$@" +else + exec "$@" +fi diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..dbcb9a1 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +*~ +*.bak +**/.envrc +**/.DS_store + +/pages-server diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml new file mode 100644 index 0000000..1119052 --- /dev/null +++ b/.gitea/workflows/build.yml @@ -0,0 +1,21 @@ +--- + +name: Build + +on: + push: + branches: [main] + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v3 + - name: Setup Go + uses: actions/setup-go@v4 + with: + go-version: '>=1.18.0' + - name: Build Binary + run: make build diff --git a/.gitignore b/.gitignore index 9e5d14a..dbcb9a1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ -/caddy -/.idea -*.iml -/Caddyfile.local \ No newline at end of file +*~ +*.bak +**/.envrc +**/.DS_store + +/pages-server diff --git a/Caddyfile b/Caddyfile deleted file mode 100644 index abe9668..0000000 --- a/Caddyfile +++ /dev/null @@ -1,47 +0,0 @@ -{ - order gitea before file_server - auto_https disable_redirects -} - -(default) { - # Gitea 服务器地址 - server https://gitea.com - # Gitea Token,需要 organization:read、repository:read、user:read 权限 - token please-replace-it - # 默认域名,类似于 Github 的 github.io - domain example.com - # CNAME 配置保存地址 - # shared: 在 caddy 实例中共享 alias,一般不建议使用 - alias path/to/file shared - # 配置缓存 (缓存刷新时间, 文件缓存时间 , 最大单文件缓存大小) - cache 30s 24h 1MB - # 默认 返回 Header,可以配置同源策略或更多内容 - headers { - Access-Control-Allow-Origin * - } - errors { - # 默认 404 页面,可填写路径或者 URL - 404 path/to/file - - # 默认 40x 页面,可填写路径或者 URL - 40x path/to/file - - # 默认 50x 页面,可填写路径或者 URL - 50x path/to/file - - # 默认 500 页面,可填写路径或者 URL - 500 path/to/file - } - # 开启重定向 scheme port - redirect https 302 -} - -http:// { - import default -} - -https:// { - ## 填入 https 配置 - # tls - import default -} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 30a80cd..77dc65a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,57 @@ -FROM docker.io/library/caddy:2.8-builder-alpine as builder -RUN mkdir -p /usr/local/src -COPY go.mod go.sum caddyfile.go /usr/local/src/ -COPY pages /usr/local/src/pages -WORKDIR /usr/local/src -RUN ls && xcaddy build \ - --with github.com/d7z-project/caddy-gitea-pages=./ -FROM docker.io/library/caddy:2.8 -COPY --from=builder /usr/local/src/caddy /usr/bin/caddy \ No newline at end of file +# Build +FROM golang:alpine AS build + +RUN apk add --no-cache -U build-base git make + +RUN mkdir -p /src + +WORKDIR /src + +# Copy Makefile +COPY Makefile ./ + +# Install deps +RUN make deps + +# Copy go.mod and go.sum and install and cache dependencies +COPY go.mod . +COPY go.sum . + +# Copy sources +COPY *.go ./ +COPY ./gitea/*.go ./gitea/ + +# Version/Commit (there there is no .git in Docker build context) +# NOTE: This is fairly low down in the Dockerfile instructions so +# we don't break the Docker build cache just be changing +# unrelated files that actually haven't changed but caused the +# COMMIT value to change. +ARG VERSION="0.0.0" +ARG COMMIT="HEAD" +ARG BUILD="" + +# Build server binary +RUN make server VERSION=$VERSION COMMIT=$COMMIT BUILD=$BUILD + +# Runtime +FROM alpine:latest + +RUN apk --no-cache -U add ca-certificates tzdata + +ENV PUID=1000 +ENV PGID=1000 + +RUN mkdir -p /data && chown -R nobody:nobody /data + +EXPOSE 8000/tcp + +VOLUME /data + +WORKDIR / + +# force cgo resolver +ENV GODEBUG=netdns=cgo + +COPY --from=build /src/pages-server /usr/local/bin/pages-server + +CMD ["pages-server"] \ No newline at end of file diff --git a/LICENSE b/LICENSE index 261eeb9..db187b3 100644 --- a/LICENSE +++ b/LICENSE @@ -1,201 +1,24 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ +MIT License - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +Copyright (C) 2023-present James Mills - 1. Definitions. +pages-server is covered by the MIT license:: - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. - "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. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Makefile b/Makefile index 8a37385..01e55d7 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,87 @@ -VERSION := 0.0.2 +-include environ.inc -dev: - @xcaddy run v2.8.4 -c Caddyfile.local +export CGO_ENABLED=0 +VERSION ?= $(shell git describe --abbrev=0 --tags 2>/dev/null) +COMMIT ?= $(shell git rev-parse --short HEAD) +BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD) +BUILD ?= $(shell git show -s --pretty=format:%cI) +GOCMD=go -fmt: - @go fmt +DESTDIR=/usr/local/bin -image: - @podman build -t ghcr.io/d7z-project/caddy-gitea-pages:$(VERSION) -f Dockerfile . \ No newline at end of file +ifeq ($(LOCAL), 1) +IMAGE := r.mills.io/prologic/pages-server +TAG := dev +else +ifeq ($(BRANCH), main) +IMAGE := prologic/pages-server +TAG := latest +else +IMAGE := prologic/pages-server +TAG := dev +endif +endif + +ifndef $$VERSION +VERSION := "0.0.0" +endif + +all: help + +.PHONY: help +help: ## Show this help message + @echo "pages-server - a Self-Hosted Pages Server for Gitea" + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[$$()% a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) + +.PHONY: dev +dev : DEBUG=1 +dev : build ## Build debug version of pages-server (server) + @./pages-server -D + +.PHONY: build +build: ## Build the pages-server binary (server) +ifeq ($(DEBUG), 1) + @echo "Building in debug mode..." + @$(GOCMD) build $(FLAGS) -tags "netgo static_build" -installsuffix netgo \ + . +else + @$(GOCMD) build $(FLAGS) -tags "netgo static_build" -installsuffix netgo \ + . +endif + +.PHONY: install +install: build ## Install pages-server (server) to $DESTDIR + @install -D -m 755 pages-server $(DESTDIR)/pages-server + +ifeq ($(PUBLISH), 1) +.PHONY: image +image: generate ## Build the Docker image + @docker buildx build \ + --platform linux/amd64,linux/arm64 --push -t $(IMAGE):$(TAG) . +else +.PHONY: image +image: generate + @docker build \ + -t $(IMAGE):$(TAG) . +endif + +.PHONY: fmt +fmt: ## Format sources files + @$(GOCMD) fmt ./... + +.PHONY: test +test: ## Run test suite + @CGO_ENABLED=1 $(GOCMD) test -v -cover -race ./... + +.PHONY: coverage +coverage: ## Get test coverage report + @CGO_ENABLED=1 $(GOCMD) test -v -cover -race -cover -coverprofile=coverage.out ./... + @$(GOCMD) tool cover -html=coverage.out + +.PHONY: clean +clean: ## Remove untracked files + @git clean -f -d -x + +.PHONY: clean-all +clean-all: ## Remove untracked and Git ignored files + @git clean -f -d -X diff --git a/README.md b/README.md index 27f2bd3..0315af8 100644 --- a/README.md +++ b/README.md @@ -1,83 +1,32 @@ -# Gitea Pages +# pages-server -[English (Google TR)](./README_en.md) | 中文 +> A prototype [Gitea](https://gitea.io) Pages server ala Github Pages (_or Vercal, Netlify, etc_). -> 参照 Github Pages 实现的 Gitea Pages +Currently supports the following: -## 安装说明 +- Proxies `*.` +- Option 1: Repo with `gitea-pages` branch + `gitea-pages` topic => `https://.//` +- Option 2: Repo of the form `.` with `gitea-pages` branch and gitea-pages topic => `https://.` -此处需要用到 `xcaddy` 工具,使用如下命令生成 Caddy 执行文件, -如果 `xcaddy` 不存在,需先前往 [caddyserver/xcaddy](https://github.com/caddyserver/xcaddy/releases) 安装 `xcaddy`, -同时安装好 Golang 1.22 +Where `` is the domain name and instance of your Gitea Pages server. -```bash -xcaddy build v2.8.4 --with github.com/d7z-project/caddy-gitea-pages -# 列出当前模块 -./caddy list-modules | grep gitea -``` +Demo sites: -当前项目也提供 `linux/amd64` 和 `linux/arm64` 的镜像: +- https://prologic.pages.mills.io/test/ serviced from https://git.mills.io/prologic/test (Option 1) +- https://actions.pages.mills.io/ serviced from https://git.mills.io/actions/actions.pages.mills.io (Option 2) -```bash -docker pull ghcr.io/d7z-project/caddy-gitea-pages:nightly -``` +## Quick Start -具体配置说明参考 `docker.io/library/caddy` 镜像。 +TBD -## 配置说明 +## Features -安装后 Caddy 后, 在 `Caddyfile` 写入如下配置: +- Proxies `./` => `owner/repo` +- Proxies `.` => `owner/subdomain` +- Automatically sets MIME types on served content. +- Ues `gitea-pages` as an "opt-in" topic label on repos. +- Content is served from a `gitea-pages` branch. -```conf -{ - order gitea before file_server -} +## License -:80 -gitea { - # Gitea 服务器地址 - server https://gitea.com - # Gitea Token - token please-replace-it - # 默认域名,类似于 Github 的 github.io - domain example.com -} -``` - -其中,token 需要如下权限: - -- `organization:read` -- `repository:read` -- `user:read` - -更详细的配置可查看 [Caddyfile](./Caddyfile) - -## 使用说明 - -仓库 `https://gitea.com/owner/repo.git` 对应示例配置中的 `owner.example.com/repo` - -如需访问 `CNAME` 配置的域名,则需要先访问仓库对应的 `.example.com/` 域名, 此操作只需完成一次。 - -**注意**: 需要仓库存在 `gh-pages` 分支和分支内存在 `index.html` 文件才可访问,如果配置后仍无法访问可重启 Caddy 来清理缓存。 - -### 文件回退策略 - -- URL 末尾为 `/` 时将自动追加 `index.html` -- 未找到文件时,如果存在 `404.html` 将使用此文件,响应 404 状态码 -- 如果仓库带有 `routes-history` 和 `routes-hash` 标签时,默认回退使用 `index.html`, 同时返回 200 状态码 - -## TODO - -- [x] 支持 CNAME 自定义路径 (仅适用于 HTTP 模式,不处理 acme 相关的内容) -- [x] 支持内容缓存 -- [ ] 优化并发模型和处理竞争问题 -- [ ] 支持 Http Range 断点续传 -- [ ] 支持 oauth2 登录访问私有页面 - -## 致谢 - -此项目参考了 [42wim/caddy-gitea](https://github.com/42wim/caddy-gitea) - -## LICENSE - -此项目使用 [Apache-2.0](./LICENSE) +`pages-server` is licensed under the terms of the [MIT License](./LICENSE). diff --git a/README_en.md b/README_en.md deleted file mode 100644 index 7b15138..0000000 --- a/README_en.md +++ /dev/null @@ -1,67 +0,0 @@ -# Gitea Pages Caddy Plugin - -English (Google TR) | [中文](./README.md) - -> Gitea Pages implemented with reference to Github Pages. - -## Installation Instructions - -`xcaddy` utility is required to generate the Caddy executable with the following command - -```bash -xcaddy build --with github.com/d7z-project/caddy-gitea-pages -# List the current modules -. /caddy list-modules | grep gitea -``` - -We also provides `linux/amd64` and `linux/arm64` images: - -```bash -docker pull ghcr.io/d7z-project/caddy-gitea-pages:nightly -``` - -## Configuration Notes - -After installing Caddy, write the following configuration in `Caddyfile`. - -```conf -{ - order gitea before file_server -} - -:80 -gitea { - # Gitea server address - server https://gitea.com - # Gitea Token - token please-replace-it - # Default domain, similar to Github's github.io - domain example.com -} - -``` - -The token requires the following permissions: - -- `organization:read` -- `repository:read` -- `user:read` - -More detailed configuration can be found in [Caddyfile](./Caddyfile) - - -## Usage Notes - -The repository `https://gitea.com/owner/repo.git` corresponds to `owner.example.com/repo` in the example configuration. - -To access the `CNAME` configured domain, you need to access the `.example.com/` domain of the repository, which needs to be done only once. - -**Note**: You need to have `gh-pages` branch and `index.html` file in the branch to access the repository, if you still can't access it, you can restart Caddy to clear the cache. - -## Acknowledgments - -This project was inspired by [42wim/caddy-gitea](https://github.com/42wim/caddy-gitea). - -## LICENSE - -uses [Apache-2.0](./LICENSE) diff --git a/caddyfile.go b/caddyfile.go deleted file mode 100644 index 54acea0..0000000 --- a/caddyfile.go +++ /dev/null @@ -1,246 +0,0 @@ -package pages - -import ( - "fmt" - "github.com/alecthomas/units" - "github.com/caddyserver/caddy/v2" - "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" - "github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile" - "github.com/caddyserver/caddy/v2/modules/caddyhttp" - "github.com/d7z-project/caddy-gitea-pages/pages" - "github.com/pkg/errors" - "go.uber.org/zap" - "io" - "net/http" - "os" - "strconv" - "strings" - "time" -) - -func init() { - middle := &Middleware{ - Config: &pages.MiddlewareConfig{}, - } - caddy.RegisterModule(middle) - httpcaddyfile.RegisterHandlerDirective("gitea", parseCaddyfile(middle)) -} - -func (m *Middleware) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { - for d.Next() { - for n := d.Nesting(); d.NextBlock(n); { - switch d.Val() { - case "server": - d.Args(&m.Config.Server) - case "token": - d.Args(&m.Config.Token) - case "cache": - remainingArgs := d.RemainingArgs() - if len(remainingArgs) != 3 { - return d.Errf("expected 3 argument for 'cache'; got %v", remainingArgs) - } - var err error - m.Config.CacheTimeout, err = time.ParseDuration(remainingArgs[0]) - if err != nil { - return d.Errf("invalid duration: %v", err) - } - m.Config.CacheRefresh, err = time.ParseDuration(remainingArgs[1]) - if err != nil { - return d.Errf("invalid duration: %v", err) - } - size, err := units.ParseBase2Bytes(remainingArgs[2]) - if err != nil { - return d.Errf("invalid CacheSize: %v", err) - } - m.Config.CacheMaxSize = int(size) - case "domain": - d.Args(&m.Config.Domain) - case "alias": - remainingArgs := d.RemainingArgs() - if len(remainingArgs) == 0 { - return d.Errf("expected 2 argument for 'alias'; got %v", remainingArgs) - } - if len(remainingArgs) == 1 { - m.Config.Alias = remainingArgs[0] - } - if len(remainingArgs) == 2 && remainingArgs[1] == "shared" { - m.Config.Alias = remainingArgs[0] - m.Config.SharedAlias = true - } - case "headers": - if d.NextArg() { - return d.ArgErr() - } - for nesting := d.Nesting(); d.NextBlock(nesting); { - args := []string{d.Val()} - args = append(args, d.RemainingArgs()...) - if len(args) != 2 { - return d.Errf("expected 2 arguments, got %d", len(args)) - } - if m.Config.CustomHeaders == nil { - m.Config.CustomHeaders = make(map[string]string) - } - m.Config.CustomHeaders[args[0]] = args[1] - } - case "errors": - if d.NextArg() { - return d.ArgErr() - } - for nesting := d.Nesting(); d.NextBlock(nesting); { - args := []string{d.Val()} - args = append(args, d.RemainingArgs()...) - if len(args) != 2 { - return d.Errf("expected 2 arguments, got %d", len(args)) - } - body, err := parseBody(args[1]) - if err != nil { - return d.Errf("failed to parse %s: %v", args[0], err) - } - if m.Config.ErrorPages == nil { - m.Config.ErrorPages = make(map[string]string) - } - m.Config.ErrorPages[strings.ToLower(args[0])] = body - } - case "redirect": - remainingArgs := d.RemainingArgs() - if len(remainingArgs) != 2 { - return d.Errf("expected 2 arguments, got %d", len(remainingArgs)) - } - code, err := strconv.Atoi(remainingArgs[1]) - if err != nil { - return d.WrapErr(err) - } - m.Config.AutoRedirect = &pages.AutoRedirect{ - Enabled: true, - Scheme: remainingArgs[0], - Code: code, - } - default: - return d.Errf("unrecognized subdirective '%s'", d.Val()) - } - } - } - return nil -} - -func parseBody(path string) (string, error) { - fileData, err := os.ReadFile(path) - if err == nil { - return string(fileData), nil - } else if strings.HasPrefix(path, "http://") || - strings.HasPrefix(path, "https://") { - resp, err := http.Get(path) - if err != nil { - return "", err - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - return "", errors.New(resp.Status) - } - all, err := io.ReadAll(resp.Body) - if err != nil { - return "", err - } - return string(all), nil - } - return "", err -} - -func parseCaddyfile(middleware *Middleware) func(httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) { - return func(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) { - err := middleware.UnmarshalCaddyfile(h.Dispenser) - if err != nil { - return nil, err - } - if middleware.Config.ErrorPages == nil { - middleware.Config.ErrorPages = make(map[string]string) - } - if middleware.Config.CustomHeaders == nil { - middleware.Config.CustomHeaders = make(map[string]string) - } - if middleware.Config.AutoRedirect == nil { - middleware.Config.AutoRedirect = &pages.AutoRedirect{ - Enabled: false, - } - } - if middleware.Config.CacheRefresh <= 0 { - middleware.Config.CacheRefresh = 1 * time.Minute - } - if middleware.Config.CacheTimeout <= 0 { - middleware.Config.CacheTimeout = 3 * time.Minute - } - if middleware.Config.CacheMaxSize <= 0 { - middleware.Config.CacheMaxSize = 3 * 1024 * 1024 - } - return middleware, nil - } -} - -type Middleware struct { - Config *pages.MiddlewareConfig `json:"config"` - Logger *zap.Logger `json:"-"` - Client *pages.PageClient `json:"-"` -} - -func (m *Middleware) ServeHTTP( - writer http.ResponseWriter, - request *http.Request, - handler caddyhttp.Handler, -) error { - - type stackTracer interface { - StackTrace() errors.StackTrace - } - err := m.Client.Route(writer, request) - if errors.Is(err, pages.ErrorNotMatches) { - return handler.ServeHTTP(writer, request) - } else { - if err != nil { - if err, ok := err.(stackTracer); ok { - for _, f := range err.StackTrace() { - fmt.Printf("%+s:%d\n", f, f) - } - } - } - return err - } -} - -func (m *Middleware) CaddyModule() caddy.ModuleInfo { - return caddy.ModuleInfo{ - ID: "http.handlers.gitea", - New: func() caddy.Module { - return new(Middleware) - }, - } -} - -func (m *Middleware) Validate() error { - return m.Client.Validate() -} - -func (m *Middleware) Cleanup() error { - m.Logger.Info("cleaning up gitea middleware.") - return m.Client.Close() -} - -func (m *Middleware) Provision(ctx caddy.Context) error { - var err error - m.Logger = ctx.Logger() // g.Logger is a *zap.Logger - m.Client, err = pages.NewPageClient( - m.Config, - m.Logger, - ) - if err != nil { - return err - } - return nil -} - -var ( - _ caddy.Provisioner = (*Middleware)(nil) - _ caddy.CleanerUpper = (*Middleware)(nil) - _ caddy.Validator = (*Middleware)(nil) - _ caddyhttp.MiddlewareHandler = (*Middleware)(nil) - _ caddyfile.Unmarshaler = (*Middleware)(nil) -) diff --git a/docker-stack.yml b/docker-stack.yml new file mode 100644 index 0000000..cfcec45 --- /dev/null +++ b/docker-stack.yml @@ -0,0 +1,32 @@ +--- +version: "3.8" + +services: + server: + image: prologic/pages-server:latest + environment: + - DOMAIN=${DOMAIN:?not set} + - GITEA_URL=${GITEA_URL:?not set} + - GITEA_TOKEN=${GITEA_TOKEN:?not set} + networks: + - traefik + deploy: + replicas: 1 + labels: + - traefik.enable=true + - traefik.docker.network=traefik + - traefik.http.services.pages.loadbalancer.server.port=8000 + - traefik.http.routers.pages.rule=HostRegexp(`{subdomain:.+}.${DOMAIN:?not set}`) + - traefik.http.routers.pages.priority=2 + resources: + reservations: + cpus: "0.1" + memory: 64M + limits: + memory: 128M + restart_policy: + condition: any + +networks: + traefik: + external: true diff --git a/gitea/frontmatter.go b/gitea/frontmatter.go new file mode 100644 index 0000000..d85cfc2 --- /dev/null +++ b/gitea/frontmatter.go @@ -0,0 +1,180 @@ +// Package gitea ... +// Taken from caddy source code (https://github.com/mholt/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 gitea + +import ( + "bytes" + "encoding/json" + "fmt" + "strings" + "unicode" + + "github.com/BurntSushi/toml" + chromahtml "github.com/alecthomas/chroma/v2/formatters/html" + "github.com/yuin/goldmark" + highlighting "github.com/yuin/goldmark-highlighting/v2" + "github.com/yuin/goldmark/extension" + "github.com/yuin/goldmark/parser" + gmhtml "github.com/yuin/goldmark/renderer/html" + "gopkg.in/yaml.v3" +) + +func extractFrontMatter(input string) (map[string]any, string, error) { + // get the bounds of the first non-empty line + var firstLineStart, firstLineEnd int + lineEmpty := true + for i, b := range input { + if b == '\n' { + firstLineStart = firstLineEnd + if firstLineStart > 0 { + firstLineStart++ // skip newline character + } + firstLineEnd = i + if !lineEmpty { + break + } + continue + } + lineEmpty = lineEmpty && unicode.IsSpace(b) + } + firstLine := input[firstLineStart:firstLineEnd] + + // ensure residue windows carriage return byte is removed + firstLine = strings.TrimSpace(firstLine) + + // see what kind of front matter there is, if any + var closingFence []string + var fmParser func([]byte) (map[string]any, error) + for _, fmType := range supportedFrontMatterTypes { + if firstLine == fmType.FenceOpen { + closingFence = fmType.FenceClose + fmParser = fmType.ParseFunc + } + } + + if fmParser == nil { + // no recognized front matter; whole document is body + return nil, input, nil + } + + // find end of front matter + var fmEndFence string + fmEndFenceStart := -1 + for _, fence := range closingFence { + index := strings.Index(input[firstLineEnd:], "\n"+fence) + if index >= 0 { + fmEndFenceStart = index + fmEndFence = fence + break + } + } + if fmEndFenceStart < 0 { + return nil, "", fmt.Errorf("unterminated front matter") + } + fmEndFenceStart += firstLineEnd + 1 // add 1 to account for newline + + // extract and parse front matter + frontMatter := input[firstLineEnd:fmEndFenceStart] + fm, err := fmParser([]byte(frontMatter)) + if err != nil { + return nil, "", err + } + + // the rest is the body + body := input[fmEndFenceStart+len(fmEndFence):] + + return fm, body, nil +} + +func yamlFrontMatter(input []byte) (map[string]any, error) { + m := make(map[string]any) + err := yaml.Unmarshal(input, &m) + return m, err +} + +func tomlFrontMatter(input []byte) (map[string]any, error) { + m := make(map[string]any) + err := toml.Unmarshal(input, &m) + return m, err +} + +func jsonFrontMatter(input []byte) (map[string]any, error) { + input = append([]byte{'{'}, input...) + input = append(input, '}') + m := make(map[string]any) + err := json.Unmarshal(input, &m) + return m, err +} + +type parsedMarkdownDoc struct { + Meta map[string]any `json:"meta,omitempty"` + Body string `json:"body,omitempty"` +} + +type frontMatterType struct { + FenceOpen string + FenceClose []string + ParseFunc func(input []byte) (map[string]any, error) +} + +var supportedFrontMatterTypes = []frontMatterType{ + { + FenceOpen: "---", + FenceClose: []string{"---", "..."}, + ParseFunc: yamlFrontMatter, + }, + { + FenceOpen: "+++", + FenceClose: []string{"+++"}, + ParseFunc: tomlFrontMatter, + }, + { + FenceOpen: "{", + FenceClose: []string{"}"}, + ParseFunc: jsonFrontMatter, + }, +} + +func markdown(input []byte) ([]byte, error) { + md := goldmark.New( + goldmark.WithExtensions( + extension.GFM, + extension.Footnote, + highlighting.NewHighlighting( + highlighting.WithFormatOptions( + chromahtml.WithClasses(true), + ), + ), + ), + goldmark.WithParserOptions( + parser.WithAutoHeadingID(), + ), + goldmark.WithRendererOptions( + gmhtml.WithUnsafe(), // TODO: this is not awesome, maybe should be configurable? + ), + ) + + buf := bufPool.Get().(*bytes.Buffer) + buf.Reset() + + defer bufPool.Put(buf) + + if err := md.Convert(input, buf); err != nil { + return input, err + } + + return buf.Bytes(), nil +} diff --git a/gitea/fs.go b/gitea/fs.go new file mode 100644 index 0000000..01d5908 --- /dev/null +++ b/gitea/fs.go @@ -0,0 +1,93 @@ +package gitea + +import ( + "io" + "io/fs" + "time" +) + +type fileInfo struct { + size int64 + isdir bool + name string +} + +type openFile struct { + content []byte + offset int64 + name string + isdir bool +} + +func (g fileInfo) Name() string { + return g.name +} + +func (g fileInfo) Size() int64 { + return g.size +} + +func (g fileInfo) Mode() fs.FileMode { + return 0o444 +} + +func (g fileInfo) ModTime() time.Time { + return time.Time{} +} + +func (g fileInfo) Sys() any { + return nil +} + +func (g fileInfo) IsDir() bool { + return g.isdir +} + +var _ io.Seeker = (*openFile)(nil) + +func (o *openFile) Close() error { + return nil +} + +func (o *openFile) Stat() (fs.FileInfo, error) { + return fileInfo{ + size: int64(len(o.content)), + isdir: o.isdir, + name: o.name, + }, nil +} + +func (o *openFile) Read(b []byte) (int, error) { + if o.offset >= int64(len(o.content)) { + return 0, io.EOF + } + + if o.offset < 0 { + return 0, &fs.PathError{Op: "read", Path: o.name, Err: fs.ErrInvalid} + } + + n := copy(b, o.content[o.offset:]) + + o.offset += int64(n) + + return n, nil +} + +func (o *openFile) Seek(offset int64, whence int) (int64, error) { + switch whence { + case 0: + offset += 0 + case 1: + offset += o.offset + case 2: + offset += int64(len(o.content)) + } + + if offset < 0 || offset > int64(len(o.content)) { + return 0, &fs.PathError{Op: "seek", Path: o.name, Err: fs.ErrInvalid} + } + + o.offset = offset + + return offset, nil +} diff --git a/gitea/gitea.go b/gitea/gitea.go new file mode 100644 index 0000000..92a837e --- /dev/null +++ b/gitea/gitea.go @@ -0,0 +1,218 @@ +package gitea + +import ( + "bytes" + "fmt" + "io" + "io/fs" + "log" + "net/http" + "net/url" + "strings" + "sync" + + "code.gitea.io/sdk/gitea" +) + +const ( + defaultPagesRef = "gitea-pages" + defaultPagesTopic = "gitea-pages" +) + +// Client ... +type Client struct { + cli *gitea.Client + url string + domain string + token string +} + +// NewClient ... +func NewClient(url, token, domain string) (*Client, error) { + cli, err := gitea.NewClient(url, gitea.SetToken(token), gitea.SetGiteaVersion("")) + if err != nil { + return nil, err + } + + return &Client{ + cli: cli, + url: url, + domain: domain, + token: token, + }, nil +} + +// Open ... +func (c *Client) Open(user, path string) (fs.File, error) { + log.Printf("user: %s", user) + log.Printf("path: %s", path) + + var ( + repo string + filepath string + ) + + parts := strings.Split(strings.TrimLeft(path, "/"), "/") + log.Printf("parts: %d #%v", len(parts), parts) + if len(parts) > 1 { + repo = parts[0] + filepath = strings.Join(parts[1:], "/") + } else { + repo = fmt.Sprintf("%s.%s", user, c.domain) + filepath = path + } + log.Printf("repo: %s", repo) + + // if path is empty they want to have the index.html + if filepath == "" || filepath == "/" { + filepath = "index.html" + } + + // If it's a dir, give them index.html + if strings.HasSuffix(filepath, "/") { + filepath += "index.html" + } + + allowed := c.allowsPages(user, repo) + log.Printf("allowed? %t", allowed) + if !allowed && repo != fmt.Sprintf("%s.%s", user, c.domain) { + repo = fmt.Sprintf("%s.%s", user, c.domain) + if c.allowsPages(user, repo) { + filepath = path + } else { + return nil, fs.ErrNotExist + } + } + + res, err := c.getRawFileOrLFS(user, repo, filepath, defaultPagesRef) + if err != nil { + return nil, err + } + + if strings.HasSuffix(filepath, ".md") { + res, err = handleMD(res) + if err != nil { + return nil, err + } + } + + return &openFile{ + content: res, + name: filepath, + }, nil +} + +func (c *Client) getRawFileOrLFS(owner, repo, filepath, ref string) ([]byte, error) { + var ( + giteaURL string + err error + ) + + // TODO: make pr for go-sdk + // gitea sdk doesn't support "media" type for lfs/non-lfs + giteaURL, err = url.JoinPath(c.url+"/api/v1/repos/", owner, repo, "media", filepath) + if err != nil { + return nil, err + } + + giteaURL += "?ref=" + url.QueryEscape(ref) + + req, err := http.NewRequest(http.MethodGet, giteaURL, nil) + if err != nil { + return nil, err + } + + req.Header.Add("Authorization", "token "+c.token) + + res, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + + switch res.StatusCode { + case http.StatusNotFound: + return nil, fs.ErrNotExist + case http.StatusOK: + default: + return nil, fmt.Errorf("unexpected status code '%d'", res.StatusCode) + } + + data, err := io.ReadAll(res.Body) + if err != nil { + return nil, err + } + defer res.Body.Close() + + return data, nil +} + +var bufPool = sync.Pool{ + New: func() any { + return new(bytes.Buffer) + }, +} + +func handleMD(res []byte) ([]byte, error) { + meta, body, err := extractFrontMatter(string(res)) + if err != nil { + return nil, err + } + + html, err := markdown([]byte(body)) + if err != nil { + return nil, err + } + + title, _ := meta["title"].(string) + + res = append([]byte("\n\n\n

"), []byte(title)...) + res = append(res, []byte("

")...) + res = append(res, html...) + res = append(res, []byte("")...) + + return res, nil +} + +func (c *Client) repoTopics(owner, repo string) ([]string, error) { + repos, _, err := c.cli.ListRepoTopics(owner, repo, gitea.ListRepoTopicsOptions{}) + return repos, err +} + +func (c *Client) hasRepoBranch(owner, repo, branch string) bool { + b, _, err := c.cli.GetRepoBranch(owner, repo, branch) + if err != nil { + return false + } + + return b.Name == branch +} + +func (c *Client) allowsPages(owner, repo string) bool { + topics, err := c.repoTopics(owner, repo) + if err != nil { + log.Printf("error finding topics for %s/%s: %s", owner, repo, err) + return false + } + + for _, topic := range topics { + if topic == defaultPagesTopic { + return true + } + } + + return false +} + +func splitName(name string) (string, string, string) { + parts := strings.Split(name, "/") + + // parts contains: ["owner", "repo", "filepath"] + switch len(parts) { + case 1: + return parts[0], "", "" + case 2: + return parts[0], parts[1], "" + default: + return parts[0], parts[1], strings.Join(parts[2:], "/") + } +} diff --git a/go.mod b/go.mod index 02060ac..ca4de04 100644 --- a/go.mod +++ b/go.mod @@ -1,126 +1,20 @@ -module github.com/d7z-project/caddy-gitea-pages +module git.mills.io/prologic/pages-server -go 1.22.4 +go 1.20 require ( - code.gitea.io/sdk/gitea v0.18.0 - github.com/Masterminds/sprig/v3 v3.2.3 - github.com/caddyserver/caddy/v2 v2.8.4 - github.com/orcaman/concurrent-map/v2 v2.0.1 + code.gitea.io/sdk/gitea v0.15.1 + github.com/BurntSushi/toml v1.3.2 + github.com/alecthomas/chroma/v2 v2.2.0 + github.com/yuin/goldmark v1.5.6 + github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc + gopkg.in/yaml.v3 v3.0.1 ) require ( - github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 - github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/pkg/errors v0.9.1 - go.uber.org/zap v1.27.0 -) - -require ( - filippo.io/edwards25519 v1.1.0 // indirect - github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect - github.com/Masterminds/goutils v1.1.1 // indirect - github.com/Masterminds/semver/v3 v3.2.1 // indirect - github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/antlr4-go/antlr/v4 v4.13.1 // indirect - github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b // indirect - github.com/beorn7/perks v1.0.1 // indirect - github.com/caddyserver/certmagic v0.21.3 // indirect - github.com/caddyserver/zerossl v0.1.3 // indirect - github.com/cespare/xxhash v1.1.0 // indirect - github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/chzyer/readline v1.5.1 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect - github.com/davidmz/go-pageant v1.0.2 // indirect - github.com/dgraph-io/badger v1.6.2 // indirect - github.com/dgraph-io/badger/v2 v2.2007.4 // indirect - github.com/dgraph-io/ristretto v0.1.1 // indirect - github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect - github.com/dustin/go-humanize v1.0.1 // indirect - github.com/go-fed/httpsig v1.1.0 // indirect - github.com/go-jose/go-jose/v3 v3.0.3 // indirect - github.com/go-kit/kit v0.13.0 // indirect - github.com/go-kit/log v0.2.1 // indirect - github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/go-sql-driver/mysql v1.8.1 // indirect - github.com/go-task/slim-sprig/v3 v3.0.0 // indirect - github.com/golang/glog v1.2.1 // indirect - github.com/golang/protobuf v1.5.4 // indirect - github.com/golang/snappy v0.0.4 // indirect - github.com/google/cel-go v0.20.1 // indirect - github.com/google/pprof v0.0.0-20240528025155-186aa0362fba // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/hashicorp/go-version v1.7.0 // indirect - github.com/huandu/xstrings v1.4.0 // indirect - github.com/imdario/mergo v0.3.16 // indirect - github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.14.3 // indirect - github.com/jackc/pgio v1.0.0 // indirect - github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.3 // indirect - github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect - github.com/jackc/pgtype v1.14.3 // indirect - github.com/jackc/pgx/v4 v4.18.3 // indirect - github.com/klauspost/compress v1.17.8 // indirect - github.com/klauspost/cpuid/v2 v2.2.7 // indirect - github.com/libdns/libdns v0.2.2 // indirect - github.com/manifoldco/promptui v0.9.0 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect - github.com/mholt/acmez/v2 v2.0.1 // indirect - github.com/miekg/dns v1.1.59 // indirect - github.com/mitchellh/copystructure v1.2.0 // indirect - github.com/mitchellh/go-ps v1.0.0 // indirect - github.com/mitchellh/reflectwalk v1.0.2 // indirect - github.com/onsi/ginkgo/v2 v2.19.0 // indirect - github.com/prometheus/client_golang v1.19.1 // indirect - github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.53.0 // indirect - github.com/prometheus/procfs v0.15.0 // indirect - github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/quic-go v0.44.0 // indirect - github.com/rs/xid v1.5.0 // indirect - github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/shopspring/decimal v1.4.0 // indirect - github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect - github.com/slackhq/nebula v1.9.1 // indirect - github.com/smallstep/certificates v0.26.1 // indirect - github.com/smallstep/nosql v0.6.1 // indirect - github.com/smallstep/pkcs7 v0.0.0-20240411202544-a82ada2bab6b // indirect - github.com/smallstep/scep v0.0.0-20240214080410-892e41795b99 // indirect - github.com/smallstep/truststore v0.13.0 // indirect - github.com/spf13/cast v1.6.0 // indirect - github.com/spf13/cobra v1.8.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect - github.com/stoewer/go-strcase v1.3.0 // indirect - github.com/tailscale/tscert v0.0.0-20240517230440-bbccfbf48933 // indirect - github.com/urfave/cli v1.22.15 // indirect - github.com/zeebo/blake3 v0.2.3 // indirect - go.etcd.io/bbolt v1.3.10 // indirect - go.step.sm/cli-utils v0.9.0 // indirect - go.step.sm/crypto v0.46.0 // indirect - go.step.sm/linkedca v0.20.1 // indirect - go.uber.org/automaxprocs v1.5.3 // indirect - go.uber.org/mock v0.4.0 // indirect - go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap/exp v0.2.0 // indirect - golang.org/x/crypto v0.24.0 // indirect - golang.org/x/crypto/x509roots/fallback v0.0.0-20240529182030-349231f7e4e4 // indirect - golang.org/x/exp v0.0.0-20240529005216-23cca8864a10 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.26.0 // indirect - golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.21.0 // indirect - golang.org/x/term v0.21.0 // indirect - golang.org/x/text v0.16.0 // indirect - golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect - google.golang.org/grpc v1.64.1 // indirect - google.golang.org/protobuf v1.34.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - howett.net/plist v1.0.1 // indirect + github.com/dlclark/regexp2 v1.7.0 // indirect + github.com/hashicorp/go-version v1.2.1 // indirect + github.com/kr/pretty v0.3.1 // indirect + github.com/stretchr/testify v1.8.3 // indirect + gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect ) diff --git a/go.sum b/go.sum index bf4fd51..714b027 100644 --- a/go.sum +++ b/go.sum @@ -1,621 +1,61 @@ -cloud.google.com/go v0.113.0 h1:g3C70mn3lWfckKBiCVsAshabrDg01pQ0pnX1MNtnMkA= -cloud.google.com/go v0.113.0/go.mod h1:glEqlogERKYeePz6ZdkcLJ28Q2I6aERgDDErBg9GzO8= -cloud.google.com/go/auth v0.4.1 h1:Z7YNIhlWRtrnKlZke7z3GMqzvuYzdc2z98F9D1NV5Hg= -cloud.google.com/go/auth v0.4.1/go.mod h1:QVBuVEKpCn4Zp58hzRGvL0tjRGU0YqdRTdCHM1IHnro= -cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4= -cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= -cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU= -cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= -cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -cloud.google.com/go/iam v1.1.8 h1:r7umDwhj+BQyz0ScZMp4QrGXjSTI3ZINnpgU2nlB/K0= -cloud.google.com/go/iam v1.1.8/go.mod h1:GvE6lyMmfxXauzNq8NbgJbeVQNspG+tcdL/W8QO1+zE= -cloud.google.com/go/kms v1.17.1 h1:5k0wXqkxL+YcXd4viQzTqCgzzVKKxzgrK+rCZJytEQs= -cloud.google.com/go/kms v1.17.1/go.mod h1:DCMnCF/apA6fZk5Cj4XsD979OyHAqFasPuA5Sd0kGlQ= -cloud.google.com/go/longrunning v0.5.7 h1:WLbHekDbjK1fVFD3ibpFFVoyizlLRl73I7YKuAKilhU= -cloud.google.com/go/longrunning v0.5.7/go.mod h1:8GClkudohy1Fxm3owmBGid8W0pSgodEMwEAztp38Xng= -code.gitea.io/sdk/gitea v0.18.0 h1:+zZrwVmujIrgobt6wVBWCqITz6bn1aBjnCUHmpZrerI= -code.gitea.io/sdk/gitea v0.18.0/go.mod h1:IG9xZJoltDNeDSW0qiF2Vqx5orMWa7OhVWrjvrd5NpI= -filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= -filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= -github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M= -github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE= +code.gitea.io/sdk/gitea v0.15.1 h1:WJreC7YYuxbn0UDaPuWIe/mtiNKTvLN8MLkaw71yx/M= +code.gitea.io/sdk/gitea v0.15.1/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMVoHRBA= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= -github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= -github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= -github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= -github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= -github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= -github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 h1:ez/4by2iGztzR4L0zgAOR8lTQK9VlyBVVd7G4omaOQs= -github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= -github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= -github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b h1:uUXgbcPDK3KpW29o4iy7GtuappbWT0l5NaMo9H9pJDw= -github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= -github.com/aws/aws-sdk-go-v2 v1.27.0 h1:7bZWKoXhzI+mMR/HjdMx8ZCC5+6fY0lS5tr0bbgiLlo= -github.com/aws/aws-sdk-go-v2 v1.27.0/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM= -github.com/aws/aws-sdk-go-v2/config v1.27.16 h1:knpCuH7laFVGYTNd99Ns5t+8PuRjDn4HnnZK48csipM= -github.com/aws/aws-sdk-go-v2/config v1.27.16/go.mod h1:vutqgRhDUktwSge3hrC3nkuirzkJ4E/mLj5GvI0BQas= -github.com/aws/aws-sdk-go-v2/credentials v1.17.16 h1:7d2QxY83uYl0l58ceyiSpxg9bSbStqBC6BeEeHEchwo= -github.com/aws/aws-sdk-go-v2/credentials v1.17.16/go.mod h1:Ae6li/6Yc6eMzysRL2BXlPYvnrLLBg3D11/AmOjw50k= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.3 h1:dQLK4TjtnlRGb0czOht2CevZ5l6RSyRWAnKeGd7VAFE= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.3/go.mod h1:TL79f2P6+8Q7dTsILpiVST+AL9lkF6PPGI167Ny0Cjw= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.7 h1:lf/8VTF2cM+N4SLzaYJERKEWAXq8MOMpZfU6wEPWsPk= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.7/go.mod h1:4SjkU7QiqK2M9oozyMzfZ/23LmUY+h3oFqhdeP5OMiI= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7 h1:4OYVp0705xu8yjdyoWix0r9wPIRXnIzzOoUpQVHIJ/g= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7/go.mod h1:vd7ESTEvI76T2Na050gODNmNU7+OyKrIKroYTu4ABiI= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.9 h1:Wx0rlZoEJR7JwlSZcHnEa7CNjrSIyVxMFWGAaXy4fJY= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.9/go.mod h1:aVMHdE0aHO3v+f/iw01fmXV/5DbfQ3Bi9nN7nd9bE9Y= -github.com/aws/aws-sdk-go-v2/service/kms v1.32.1 h1:FARrQLRQXpCFYylIUVF1dRij6YbPCmtwudq9NBk4kFc= -github.com/aws/aws-sdk-go-v2/service/kms v1.32.1/go.mod h1:8lETO9lelSG2B6KMXFh2OwPPqGV6WQM3RqLAEjP1xaU= -github.com/aws/aws-sdk-go-v2/service/sso v1.20.9 h1:aD7AGQhvPuAxlSUfo0CWU7s6FpkbyykMhGYMvlqTjVs= -github.com/aws/aws-sdk-go-v2/service/sso v1.20.9/go.mod h1:c1qtZUWtygI6ZdvKppzCSXsDOq5I4luJPZ0Ud3juFCA= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.3 h1:Pav5q3cA260Zqez42T9UhIlsd9QeypszRPwC9LdSSsQ= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.3/go.mod h1:9lmoVDVLz/yUZwLaQ676TK02fhCu4+PgRSmMaKR1ozk= -github.com/aws/aws-sdk-go-v2/service/sts v1.28.10 h1:69tpbPED7jKPyzMcrwSvhWcJ9bPnZsZs18NT40JwM0g= -github.com/aws/aws-sdk-go-v2/service/sts v1.28.10/go.mod h1:0Aqn1MnEuitqfsCNyKsdKLhDUOr4txD/g19EfiUqgws= -github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q= -github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= -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/caddyserver/caddy/v2 v2.8.4 h1:q3pe0wpBj1OcHFZ3n/1nl4V4bxBrYoSoab7rL9BMYNk= -github.com/caddyserver/caddy/v2 v2.8.4/go.mod h1:vmDAHp3d05JIvuhc24LmnxVlsZmWnUwbP5WMjzcMPWw= -github.com/caddyserver/certmagic v0.21.3 h1:pqRRry3yuB4CWBVq9+cUqu+Y6E2z8TswbhNx1AZeYm0= -github.com/caddyserver/certmagic v0.21.3/go.mod h1:Zq6pklO9nVRl3DIFUw9gVUfXKdpc/0qwTUAQMBlfgtI= -github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA= -github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= -github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= -github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= -github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= -github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= -github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/alecthomas/chroma/v2 v2.2.0 h1:Aten8jfQwUqEdadVFFjNyjx7HTexhKP0XuqBG67mRDY= +github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs= +github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae h1:zzGwJfFlFGD94CyyYwCJeSuD32Gj9GTaSi5y9hoVzdY= +github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 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/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0= -github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE= -github.com/dgraph-io/badger v1.6.2 h1:mNw0qs90GVgGGWylh0umH5iag1j6n/PeJtNvL6KY/x8= -github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE= -github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= -github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= -github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= -github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= -github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= -github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= -github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= -github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= -github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI= -github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM= -github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= -github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= -github.com/go-kit/kit v0.4.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU= -github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= -github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= -github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= -github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= -github.com/go-stack/stack v1.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= -github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4= -github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/cel-go v0.20.1 h1:nDx9r8S3L4pE61eDdt8igGj8rf5kjYR3ILxWIpWNi84= -github.com/google/cel-go v0.20.1/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg= -github.com/google/certificate-transparency-go v1.1.8-0.20240110162603-74a5dd331745 h1:heyoXNxkRT155x4jTAiSv5BVSVkueifPUm+Q8LUXMRo= -github.com/google/certificate-transparency-go v1.1.8-0.20240110162603-74a5dd331745/go.mod h1:zN0wUQgV9LjwLZeFHnrAbQi8hzMVvEWePyk+MhPOk7k= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk= -github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU= -github.com/google/go-tpm-tools v0.4.4 h1:oiQfAIkc6xTy9Fl5NKTeTJkBTlXdHsxAofmQyxBKY98= -github.com/google/go-tpm-tools v0.4.4/go.mod h1:T8jXkp2s+eltnCDIsXR84/MTcVU9Ja7bh3Mit0pa4AY= -github.com/google/go-tspi v0.3.0 h1:ADtq8RKfP+jrTyIWIZDIYcKOMecRqNJFOew2IT0Inus= -github.com/google/go-tspi v0.3.0/go.mod h1:xfMGI3G0PhxCdNVcYr1C4C+EizojDg/TXuX5by8CiHI= -github.com/google/pprof v0.0.0-20240528025155-186aa0362fba h1:ql1qNgCyOB7iAEk8JTNM+zJrgIbnyCKX/wdlyPufP5g= -github.com/google/pprof v0.0.0-20240528025155-186aa0362fba/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= -github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= -github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= -github.com/googleapis/gax-go/v2 v2.12.4 h1:9gWcmF85Wvq4ryPFvGFaOgPIs1AQX0d0bcbGw4Z96qg= -github.com/googleapis/gax-go/v2 v2.12.4/go.mod h1:KYEYLorsnIGDi/rPC8b5TdlB9kbKoFubselGIoBMCwI= -github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= -github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= -github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= -github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= -github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= -github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= -github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= -github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= -github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= -github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= -github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= -github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w= -github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM= -github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= -github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= -github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= -github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= -github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= -github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= -github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag= -github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA= -github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= -github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= -github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= -github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= -github.com/jackc/pgtype v1.14.3 h1:h6W9cPuHsRWQFTWUZMAKMgG5jSwQI0Zurzdvlx3Plus= -github.com/jackc/pgtype v1.14.3/go.mod h1:aKeozOde08iifGosdJpz9MBZonJOUJxqNpPBcMJTlVA= -github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= -github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= -github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= -github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= -github.com/jackc/pgx/v4 v4.18.3 h1:dE2/TrEsGX3RBprb3qryqSV9Y60iZN1C6i8IrmW9/BA= -github.com/jackc/pgx/v4 v4.18.3/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= -github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= -github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= -github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= -github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= -github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= +github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= +github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= -github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s= -github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= -github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= -github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= -github.com/mholt/acmez/v2 v2.0.1 h1:3/3N0u1pLjMK4sNEAFSI+bcvzbPhRpY383sy1kLHJ6k= -github.com/mholt/acmez/v2 v2.0.1/go.mod h1:fX4c9r5jYwMyMsC+7tkYRxHibkOTgta5DIFGoe67e1U= -github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs= -github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= -github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= -github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= -github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= -github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= -github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= -github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= -github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= -github.com/orcaman/concurrent-map/v2 v2.0.1 h1:jOJ5Pg2w1oeB6PeDurIYf6k9PQ+aTITr/6lP/L/zp6c= -github.com/orcaman/concurrent-map/v2 v2.0.1/go.mod h1:9Eq3TG2oBe5FirmYWQfYO5iH1q0Jv47PLaNK++uCdOM= -github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= -github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/peterbourgon/diskv/v3 v3.0.1 h1:x06SQA46+PKIUftmEujdwSEpIx8kR+M9eLYsUxeYveU= -github.com/peterbourgon/diskv/v3 v3.0.1/go.mod h1:kJ5Ny7vLdARGU3WUuy6uzO6T0nb/2gWcT1JiBvRmb5o= -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/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 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/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= -github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= -github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= -github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= -github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.53.0 h1:U2pL9w9nmJwJDa4qqLQ3ZaePJ6ZTwt7cMD3AG3+aLCE= -github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U= -github.com/prometheus/procfs v0.15.0 h1:A82kmvXJq2jTu5YUhSGNlYoxh85zLnKgPz4bMZgI5Ek= -github.com/prometheus/procfs v0.15.0/go.mod h1:Y0RJ/Y5g5wJpkTisOtqwDSo4HwhGmLB4VQSw2sQJLHk= -github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= -github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/quic-go v0.44.0 h1:So5wOr7jyO4vzL2sd8/pD9Kesciv91zSk8BoFngItQ0= -github.com/quic-go/quic-go v0.44.0/go.mod h1:z4cx/9Ny9UtGITIPzmPTXh1ULfOyWh4qGQlpnPcWmek= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= -github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= -github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= -github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= -github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/schollz/jsonstore v1.1.0 h1:WZBDjgezFS34CHI+myb4s8GGpir3UMpy7vWoCeO0n6E= -github.com/schollz/jsonstore v1.1.0/go.mod h1:15c6+9guw8vDRyozGjN3FoILt0wpruJk9Pi66vjaZfg= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= -github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= -github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/slackhq/nebula v1.9.1 h1:E90JNw+QNz9RjbTKho9UGIQicx/Ppvx25MFfm6+Mqek= -github.com/slackhq/nebula v1.9.1/go.mod h1:PMJer5rZe0H/O+kUiKOL9AJ/pL9+ryzNXtSN7ABfjfM= -github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY= -github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc= -github.com/smallstep/certificates v0.26.1 h1:FIUliEBcExSfJJDhRFA/s8aZgMIFuorexnRSKQd884o= -github.com/smallstep/certificates v0.26.1/go.mod h1:OQMrW39IrGKDViKSHrKcgSQArMZ8c7EcjhYKK7mYqis= -github.com/smallstep/go-attestation v0.4.4-0.20240109183208-413678f90935 h1:kjYvkvS/Wdy0PVRDUAA0gGJIVSEZYhiAJtfwYgOYoGA= -github.com/smallstep/go-attestation v0.4.4-0.20240109183208-413678f90935/go.mod h1:vNAduivU014fubg6ewygkAvQC0IQVXqdc8vaGl/0er4= -github.com/smallstep/nosql v0.6.1 h1:X8IBZFTRIp1gmuf23ne/jlD/BWKJtDQbtatxEn7Et1Y= -github.com/smallstep/nosql v0.6.1/go.mod h1:vrN+CftYYNnDM+DQqd863ATynvYFm/6FuY9D4TeAm2Y= -github.com/smallstep/pkcs7 v0.0.0-20231024181729-3b98ecc1ca81/go.mod h1:SoUAr/4M46rZ3WaLstHxGhLEgoYIDRqxQEXLOmOEB0Y= -github.com/smallstep/pkcs7 v0.0.0-20240411202544-a82ada2bab6b h1:WwKnv9cYAjKHQ7IXQ/b88kfJjofMcjFjSV8ZXzpcMCk= -github.com/smallstep/pkcs7 v0.0.0-20240411202544-a82ada2bab6b/go.mod h1:SoUAr/4M46rZ3WaLstHxGhLEgoYIDRqxQEXLOmOEB0Y= -github.com/smallstep/scep v0.0.0-20240214080410-892e41795b99 h1:e85HuLX5/MW15yJ7yWb/PMNFW1Kx1N+DeQtpQnlMUbw= -github.com/smallstep/scep v0.0.0-20240214080410-892e41795b99/go.mod h1:4d0ub42ut1mMtvGyMensjuHYEUpRrASvkzLEJvoRQcU= -github.com/smallstep/truststore v0.13.0 h1:90if9htAOblavbMeWlqNLnO9bsjjgVv2hQeQJCi/py4= -github.com/smallstep/truststore v0.13.0/go.mod h1:3tmMp2aLKZ/OA/jnFUB0cYPcho402UG2knuJoPh4j7A= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= -github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= -github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= -github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= -github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -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/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/tailscale/tscert v0.0.0-20240517230440-bbccfbf48933 h1:pV0H+XIvFoP7pl1MRtyPXh5hqoxB5I7snOtTHgrn6HU= -github.com/tailscale/tscert v0.0.0-20240517230440-bbccfbf48933/go.mod h1:kNGUQ3VESx3VZwRwA9MSCUegIl6+saPL8Noq82ozCaU= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/urfave/cli v1.22.15 h1:nuqt+pdC/KqswQKhETJjo7pvn/k4xMUxgW6liI7XpnM= -github.com/urfave/cli v1.22.15/go.mod h1:wSan1hmo5zeyLGBjRJbzRTNk8gwoYa2B9n4q9dmRIc0= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY= -github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= -github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg= -github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ= -github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= -github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= -github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0= -go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= -go.step.sm/cli-utils v0.9.0 h1:55jYcsQbnArNqepZyAwcato6Zy2MoZDRkWW+jF+aPfQ= -go.step.sm/cli-utils v0.9.0/go.mod h1:Y/CRoWl1FVR9j+7PnAewufAwKmBOTzR6l9+7EYGAnp8= -go.step.sm/crypto v0.46.0 h1:cuVZMpDbmEsUX+atC24+VineQr4gO+zO46MxbIVai4Y= -go.step.sm/crypto v0.46.0/go.mod h1:hcr0oTS2vGRTGSZxoVYxE+RRcsd4xP3rpqt3wPwYGqc= -go.step.sm/linkedca v0.20.1 h1:bHDn1+UG1NgRrERkWbbCiAIvv4lD5NOFaswPDTyO5vU= -go.step.sm/linkedca v0.20.1/go.mod h1:Vaq4+Umtjh7DLFI1KuIxeo598vfBzgSYZUjgVJ7Syxw= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= -go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= -go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -go.uber.org/zap/exp v0.2.0 h1:FtGenNNeCATRB3CmB/yEUnjEFeJWpB/pMcy7e2bKPYs= -go.uber.org/zap/exp v0.2.0/go.mod h1:t0gqAIdh1MfKv9EwN/dLwfZnJxe9ITAZN78HEWPFWDQ= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yuin/goldmark v1.5.6 h1:COmQAWTCcGetChm3Ig7G/t8AFAN00t+o8Mt4cf7JpwA= +github.com/yuin/goldmark v1.5.6/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ= +github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/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-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= -golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= -golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= -golang.org/x/crypto/x509roots/fallback v0.0.0-20240529182030-349231f7e4e4 h1:4+O65d2kC/+OwkhzSLfWeDqJyhHHsi2LHp/m3fkWQ0I= -golang.org/x/crypto/x509roots/fallback v0.0.0-20240529182030-349231f7e4e4/go.mod h1:kNa9WdvYnzFwC79zRpLRMJbdEFlhyM5RPFBBZp/wWH8= -golang.org/x/exp v0.0.0-20240529005216-23cca8864a10 h1:vpzMC/iZhYFAjJzHU0Cfuq+w1vLLsF2vLkDrPjzKYck= -golang.org/x/exp v0.0.0-20240529005216-23cca8864a10/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= -golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo= -golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= -golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/text v0.3.0/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.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 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-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.181.0 h1:rPdjwnWgiPPOJx3IcSAQ2III5aX5tCer6wMpa/xmZi4= -google.golang.org/api v0.181.0/go.mod h1:MnQ+M0CFsfUwA5beZ+g/vCBCPXvtmZwRz2qzZk8ih1k= -google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda h1:wu/KJm9KJwpfHWhkkZGohVC6KRrc1oJNr4jwtQMOQXw= -google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda/go.mod h1:g2LLCvCeCSir/JJSWosk19BR4NVxGqHUC6rxIRsd7Aw= -google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw= -google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= -google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= -google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= -gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= -gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= -gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= gopkg.in/yaml.v2 v2.2.2/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/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -howett.net/plist v1.0.1 h1:37GdZ8tP09Q35o9ych3ehygcsL+HqKSwzctveSlarvM= -howett.net/plist v1.0.1/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= diff --git a/main.go b/main.go new file mode 100644 index 0000000..67fc536 --- /dev/null +++ b/main.go @@ -0,0 +1,68 @@ +// Package main implements a simple Gitea Pages server for hosting static websites. +package main + +import ( + "fmt" + "io" + "log" + "mime" + "net/http" + "os" + "path" + "strings" + + "git.mills.io/prologic/pages-server/gitea" +) + +// GiteaHandler ... +type GiteaHandler struct { + Client *gitea.Client + + Server string + Domain string + Token string +} + +// Init ... +func (h *GiteaHandler) Init() error { + var err error + h.Client, err = gitea.NewClient(h.Server, h.Token, h.Domain) + + return err +} + +// ServeHTTP ... +func (h *GiteaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + // remove the domain if it's set (works fine if it's empty) + user := strings.TrimRight(strings.TrimSuffix(r.Host, h.Domain), ".") + log.Printf("user: %s", user) + + f, err := h.Client.Open(user, r.URL.Path) + if err != nil { + http.Error(w, fmt.Sprintf("error resource not found: %s", err.Error()), http.StatusNotFound) + return + } + + extension := path.Ext(r.URL.Path) + mimeType := mime.TypeByExtension(extension) + w.Header().Add("content-type", mimeType) + + if _, err := io.Copy(w, f); err != nil { + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + } +} + +func main() { + handler := &GiteaHandler{ + Domain: os.Getenv("DOMAIN"), + Server: os.Getenv("GITEA_URL"), + Token: os.Getenv("GITEA_TOKEN"), + } + if err := handler.Init(); err != nil { + log.Fatalf("error initializing handler: %s", err) + } + + if err := http.ListenAndServe("0.0.0.0:8000", handler); err != nil { + log.Fatalf("error running server: %s", err) + } +} diff --git a/pages/40x.gohtml b/pages/40x.gohtml deleted file mode 100644 index c61e6a5..0000000 --- a/pages/40x.gohtml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - 404 Not Found - - -

404 Not Found

-
-
Gitea Pages
- - \ No newline at end of file diff --git a/pages/50x.gohtml b/pages/50x.gohtml deleted file mode 100644 index 35e6399..0000000 --- a/pages/50x.gohtml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - 500 Internal Error - - -

500 Internal Error

-
-
Gitea Pages
- - \ No newline at end of file diff --git a/pages/buf.go b/pages/buf.go deleted file mode 100644 index 2fa0ae9..0000000 --- a/pages/buf.go +++ /dev/null @@ -1,19 +0,0 @@ -package pages - -import ( - "bytes" -) - -type ByteBuf struct { - *bytes.Buffer -} - -func NewByteBuf(byte []byte) *ByteBuf { - return &ByteBuf{ - bytes.NewBuffer(byte), - } -} - -func (b ByteBuf) Close() error { - return nil -} diff --git a/pages/cache_domain.go b/pages/cache_domain.go deleted file mode 100644 index 628bde4..0000000 --- a/pages/cache_domain.go +++ /dev/null @@ -1,370 +0,0 @@ -package pages - -import ( - "bufio" - "bytes" - "code.gitea.io/sdk/gitea" - "crypto/sha1" - "fmt" - "github.com/patrickmn/go-cache" - "github.com/pkg/errors" - "go.uber.org/zap" - "io" - "net/http" - "slices" - "strconv" - "strings" - "sync" - "time" -) - -type DomainCache struct { - ttl time.Duration - *cache.Cache - mutexes sync.Map -} - -func (c *DomainCache) Close() error { - if c.Cache != nil { - c.Cache.Flush() - } - return nil -} - -type DomainConfig struct { - FetchTime int64 //上次刷新时间 - - PageDomain PageDomain - Exists bool // 当前项目是否为 Pages - FileCache *cache.Cache // 文件缓存 - - CNAME []string // 重定向地址 - SHA string // 缓存 SHA - DATE time.Time // 文件提交时间 - BasePath string // 根目录 - Topics map[string]bool // 存储库标记 - - Index string //默认页面 - NotFound string //不存在页面 -} - -func (receiver *DomainConfig) Close() error { - receiver.FileCache.Flush() - return nil -} -func (receiver *DomainConfig) IsRoutePage() bool { - return receiver.Topics["routes-history"] || receiver.Topics["routes-hash"] -} - -func NewDomainCache(ttl time.Duration, refreshTtl time.Duration) DomainCache { - c := cache.New(refreshTtl, 2*refreshTtl) - c.OnEvicted(func(_ string, i interface{}) { - config := i.(*DomainConfig) - if config != nil { - err := config.Close() - if err != nil { - return - } - } - }) - return DomainCache{ - ttl: ttl, - Cache: c, - mutexes: sync.Map{}, - } -} - -func fetch(client *GiteaConfig, domain *PageDomain, result *DomainConfig) error { - branches, resp, err := client.Client.ListRepoBranches(domain.Owner, domain.Repo, - gitea.ListRepoBranchesOptions{ - ListOptions: gitea.ListOptions{ - PageSize: 999, - }, - }) - // 缓存 404 内容 - if resp != nil && resp.StatusCode >= 400 && resp.StatusCode < 500 { - result.Exists = false - return nil - } - if err != nil { - return err - } - topics, resp, err := client.Client.ListRepoTopics(domain.Owner, domain.Repo, gitea.ListRepoTopicsOptions{ - ListOptions: gitea.ListOptions{ - PageSize: 999, - }, - }) - if err != nil { - return err - } - branchIndex := slices.IndexFunc(branches, func(x *gitea.Branch) bool { return x.Name == domain.Branch }) - if branchIndex == -1 { - return errors.Wrap(ErrorNotFound, "branch not found") - } - currentSHA := branches[branchIndex].Commit.ID - commitTime := branches[branchIndex].Commit.Timestamp - result.Topics = make(map[string]bool) - for _, topic := range topics { - result.Topics[strings.ToLower(topic)] = true - } - if result.SHA == currentSHA { - // 历史缓存一致,跳过 - result.FetchTime = time.Now().UnixMilli() - return nil - } - // 清理历史缓存 - if result.SHA != currentSHA { - if result.FileCache != nil { - result.FileCache.Flush() - } - result.SHA = currentSHA - result.DATE = commitTime - } - //查询是否为仓库 - result.Exists, err = client.FileExists(domain, result.BasePath+"/index.html") - if err != nil { - return err - } - if !result.Exists { - return nil - } - result.Index = "index.html" - //############# 处理 404 - if result.IsRoutePage() { - result.NotFound = "/index.html" - } else { - notFound, err := client.FileExists(domain, result.BasePath+"/404.html") - if err != nil { - return err - } - if notFound { - result.NotFound = "/404.html" - } - } - // ############ 拉取 CNAME - cname, err := client.ReadStringRepoFile(domain, "/CNAME") - if err != nil && !errors.Is(err, ErrorNotFound) { - // ignore not fond error - return err - } else if cname != "" { - // 清理重定向 - result.CNAME = make([]string, 0) - scanner := bufio.NewScanner(strings.NewReader(cname)) - for scanner.Scan() { - alias := scanner.Text() - alias = strings.TrimSpace(alias) - alias = strings.TrimPrefix(strings.TrimPrefix(alias, "https://"), "http://") - alias = strings.Split(alias, "/")[0] - if len(strings.TrimSpace(alias)) > 0 { - result.CNAME = append(result.CNAME, alias) - } - } - } - result.FetchTime = time.Now().UnixMilli() - return nil -} - -func (receiver *DomainConfig) tag(path string) string { - return fmt.Sprintf("%x", sha1.Sum([]byte( - fmt.Sprintf("%s|%s|%s", receiver.SHA, receiver.PageDomain.Key(), path)))) -} - -func (receiver *DomainConfig) withNotFoundPage( - client *GiteaConfig, - response *FakeResponse, -) error { - if receiver.NotFound == "" { - // 没有默认页面 - return ErrorNotFound - } - notFound, _ := receiver.FileCache.Get(receiver.NotFound) - if notFound == nil { - // 不存在 notfound - domain := &receiver.PageDomain - fileContext, err := client.OpenFileContext(domain, receiver.BasePath+receiver.NotFound) - if errors.Is(err, ErrorNotFound) { - //缓存 not found 不存在 - receiver.FileCache.Set(receiver.NotFound, make([]byte, 0), cache.DefaultExpiration) - return err - } else if err != nil { - return err - } - length, _ := strconv.Atoi(fileContext.Header.Get("Content-Length")) - if length > client.CacheMaxSize { - client.Logger.Debug("default page too large.") - response.Body = fileContext.Body - response.CacheModeIgnore() - } else { - // 保存缓存 - client.Logger.Debug("create default error page.") - defer fileContext.Body.Close() - defBuf, _ := io.ReadAll(fileContext.Body) - receiver.FileCache.Set(receiver.NotFound, defBuf, cache.DefaultExpiration) - response.Body = NewByteBuf(defBuf) - response.CacheModeMiss() - } - response.ContentTypeExt(receiver.NotFound) - response.Length(length) - } else { - notFound := notFound.([]byte) - if len(notFound) == 0 { - // 不存在 NotFound - return ErrorNotFound - } - response.Length(len(notFound)) - response.Body = NewByteBuf(notFound) - response.CacheModeHit() - } - client.Logger.Debug("use cache error page.") - response.ContentTypeExt(receiver.NotFound) - if receiver.IsRoutePage() { - response.StatusCode = http.StatusOK - } else { - response.StatusCode = http.StatusNotFound - } - return nil -} - -// todo: 读写加锁 -func (receiver *DomainConfig) getCachedData( - client *GiteaConfig, - path string, -) (*FakeResponse, error) { - result := NewFakeResponse() - if strings.HasSuffix(path, "/") { - path = path + "index.html" - } - for k, v := range client.CustomHeaders { - result.SetHeader(k, v) - } - result.ETag(receiver.tag(path)) - result.ContentTypeExt(path) - cacheBuf, _ := receiver.FileCache.Get(path) - // 使用缓存内容 - if cacheBuf != nil { - cacheBuf := cacheBuf.([]byte) - if len(cacheBuf) == 0 { - //使用 NotFound 内容 - client.Logger.Debug("location not found ,", zap.Any("path", path)) - return result, receiver.withNotFoundPage(client, result) - } else { - // 使用缓存 - client.Logger.Debug("location use cache ,", zap.Any("path", path)) - result.Body = ByteBuf{ - bytes.NewBuffer(cacheBuf), - } - result.Length(len(cacheBuf)) - result.CacheModeHit() - return result, nil - } - } else { - // 添加缓存 - client.Logger.Debug("location add cache ,", zap.Any("path", path)) - domain := *(&receiver.PageDomain) - domain.Branch = receiver.SHA - fileContext, err := client.OpenFileContext(&domain, receiver.BasePath+path) - if err != nil && !errors.Is(err, ErrorNotFound) { - return nil, err - } else if errors.Is(err, ErrorNotFound) { - client.Logger.Debug("location not found and src not found,", zap.Any("path", path)) - // 不存在且源不存在 - receiver.FileCache.Set(path, make([]byte, 0), cache.DefaultExpiration) - return result, receiver.withNotFoundPage(client, result) - } else { - // 源存在,执行缓存 - client.Logger.Debug("location found and set cache,", zap.Any("path", path)) - length, _ := strconv.Atoi(fileContext.Header.Get("Content-Length")) - if length > client.CacheMaxSize { - client.Logger.Debug("location too large , skip cache.", zap.Any("path", path)) - // 超过大小,回源 - result.Body = fileContext.Body - result.Length(length) - result.CacheModeIgnore() - return result, nil - } else { - client.Logger.Debug("location saved,", zap.Any("path", path)) - // 未超过大小,缓存 - body, _ := io.ReadAll(fileContext.Body) - receiver.FileCache.Set(path, body, cache.DefaultExpiration) - result.Body = NewByteBuf(body) - result.Length(len(body)) - result.CacheModeMiss() - return result, nil - } - } - } -} - -func (receiver *DomainConfig) Copy( - client *GiteaConfig, - path string, - writer http.ResponseWriter, - _ *http.Request, -) (bool, error) { - fakeResp, err := receiver.getCachedData(client, path) - if err != nil { - return false, err - } - for k, v := range fakeResp.Header { - for _, s := range v { - writer.Header().Add(k, s) - } - } - writer.Header().Add("Pages-Server-Hash", receiver.SHA) - writer.Header().Add("Last-Modified", receiver.DATE.UTC().Format(http.TimeFormat)) - writer.WriteHeader(fakeResp.StatusCode) - defer fakeResp.Body.Close() - _, err = io.Copy(writer, fakeResp.Body) - return true, err -} - -// FetchRepo 拉取 Repo 信息 -func (c *DomainCache) FetchRepo(client *GiteaConfig, domain *PageDomain) (*DomainConfig, bool, error) { - nextTime := time.Now().UnixMilli() - c.ttl.Milliseconds() - cacheKey := domain.Key() - result, _ := c.Get(cacheKey) - if result != nil { - result := result.(*DomainConfig) - if nextTime > result.FetchTime { - // 刷新旧的缓存 - result = nil - } else { - return result, true, nil - - } - } - if result == nil { - lock := c.Lock(domain) - defer lock() - if result, find := c.Get(cacheKey); find { - return result.(*DomainConfig), true, nil - } - result = &DomainConfig{ - PageDomain: *domain, - FileCache: cache.New(c.ttl, c.ttl*2), - } - if err := fetch(client, domain, result.(*DomainConfig)); err != nil { - return nil, false, err - } - err := c.Add(cacheKey, result, cache.DefaultExpiration) - if err != nil { - return nil, false, err - } - return result.(*DomainConfig), false, nil - } else { - return result.(*DomainConfig), true, nil - } - -} - -func (c *DomainCache) Lock(any *PageDomain) func() { - return c.LockAny(any.Key()) -} - -func (c *DomainCache) LockAny(any string) func() { - value, _ := c.mutexes.LoadOrStore(any, &sync.Mutex{}) - mtx := value.(*sync.Mutex) - mtx.Lock() - - return func() { mtx.Unlock() } -} diff --git a/pages/cache_owner.go b/pages/cache_owner.go deleted file mode 100644 index b1f3996..0000000 --- a/pages/cache_owner.go +++ /dev/null @@ -1,111 +0,0 @@ -package pages - -import ( - "code.gitea.io/sdk/gitea" - "github.com/patrickmn/go-cache" - "github.com/pkg/errors" - "net/http" - "strings" - "sync" - "time" -) - -type OwnerCache struct { - ttl time.Duration - *cache.Cache - mutexes sync.Map -} - -func NewOwnerCache(ttl time.Duration, cacheTtl time.Duration) OwnerCache { - return OwnerCache{ - ttl: ttl, - mutexes: sync.Map{}, - Cache: cache.New(cacheTtl, cacheTtl*2), - } -} - -type OwnerConfig struct { - FetchTime int64 `json:"fetch_time,omitempty"` - Repos map[string]bool `json:"repos,omitempty"` - LowerRepos map[string]bool `json:"lower_repos,omitempty"` -} - -func NewOwnerConfig() *OwnerConfig { - return &OwnerConfig{ - Repos: make(map[string]bool), - LowerRepos: make(map[string]bool), - } -} - -// 直接查询 Owner 信息 -func getOwner(giteaConfig *GiteaConfig, owner string) (*OwnerConfig, error) { - result := NewOwnerConfig() - repos, resp, err := giteaConfig.Client.ListOrgRepos(owner, gitea.ListOrgReposOptions{ - ListOptions: gitea.ListOptions{ - PageSize: 999, - }, - }) - if err != nil && resp.StatusCode == http.StatusNotFound { - // 调用用户接口查询 - repos, resp, err = giteaConfig.Client.ListUserRepos(owner, gitea.ListReposOptions{ - ListOptions: gitea.ListOptions{ - PageSize: 999, - }, - }) - if err != nil && resp.StatusCode == http.StatusNotFound { - return nil, errors.Wrap(ErrorNotFound, err.Error()) - } else if err != nil { - return nil, err - } - } else if err != nil { - return nil, err - } - for _, repo := range repos { - result.Repos[repo.Name] = true - result.LowerRepos[strings.ToLower(repo.Name)] = true - } - result.FetchTime = time.Now().UnixMilli() - return result, nil -} - -func (c *OwnerCache) GetOwnerConfig(giteaConfig *GiteaConfig, owner string) (*OwnerConfig, error) { - raw, _ := c.Get(owner) - // 每固定时间刷新一次 - nextTime := time.Now().UnixMilli() - c.ttl.Milliseconds() - var result *OwnerConfig - if raw != nil { - result = raw.(*OwnerConfig) - if nextTime > result.FetchTime { - //移除旧数据 - c.Delete(owner) - raw = nil - } - } - if raw == nil { - lock := c.Lock(owner) - defer lock() - if raw, find := c.Get(owner); find { - return raw.(*OwnerConfig), nil - } - //不存在缓存 - var err error - result, err = getOwner(giteaConfig, owner) - if err != nil { - return nil, errors.Wrap(err, "owner config not found") - } - c.Set(owner, result, cache.DefaultExpiration) - } - return result, nil -} - -func (c *OwnerCache) Lock(any string) func() { - value, _ := c.mutexes.LoadOrStore(any, &sync.Mutex{}) - mtx := value.(*sync.Mutex) - mtx.Lock() - - return func() { mtx.Unlock() } -} - -func (c *OwnerConfig) Exists(repo string) bool { - return c.LowerRepos[strings.ToLower(repo)] -} diff --git a/pages/client.go b/pages/client.go deleted file mode 100644 index b5ecac5..0000000 --- a/pages/client.go +++ /dev/null @@ -1,88 +0,0 @@ -package pages - -import ( - "code.gitea.io/sdk/gitea" - "go.uber.org/zap" - "strconv" - "strings" -) - -type AutoRedirect struct { - Enabled bool - Scheme string - Code int -} - -type PageClient struct { - BaseDomain string - GiteaConfig *GiteaConfig - DomainAlias *CustomDomains - ErrorPages *ErrorPages - AutoRedirect *AutoRedirect - OwnerCache *OwnerCache - DomainCache *DomainCache - logger *zap.Logger -} - -func (p *PageClient) Close() error { - if p.OwnerCache != nil { - p.OwnerCache.Cache.Flush() - } - if p.DomainCache != nil { - _ = p.DomainCache.Close() - } - return nil -} - -func NewPageClient( - config *MiddlewareConfig, - logger *zap.Logger, -) (*PageClient, error) { - options := make([]gitea.ClientOption, 0) - if config.Token != "" { - options = append(options, gitea.SetToken(config.Token)) - } - options = append(options, gitea.SetGiteaVersion("")) - client, err := gitea.NewClient(config.Server, options...) - if err != nil { - return nil, err - } - alias, err := NewCustomDomains(config.Alias, config.SharedAlias) - if err != nil { - return nil, err - } - pages, err := NewErrorPages(config.ErrorPages) - if err != nil { - return nil, err - } - ownerCache := NewOwnerCache(config.CacheRefresh, config.CacheTimeout) - giteaConfig := &GiteaConfig{ - Server: config.Server, - Token: config.Token, - Client: client, - Logger: logger, - CacheMaxSize: config.CacheMaxSize, - CustomHeaders: config.CustomHeaders, - } - domainCache := NewDomainCache(config.CacheRefresh, config.CacheTimeout) - logger.Info("gitea cache ttl " + strconv.FormatInt(config.CacheTimeout.Milliseconds(), 10) + " ms .") - return &PageClient{ - GiteaConfig: giteaConfig, - BaseDomain: "." + strings.Trim(config.Domain, "."), - DomainAlias: alias, - ErrorPages: pages, - logger: logger, - AutoRedirect: config.AutoRedirect, - DomainCache: &domainCache, - OwnerCache: &ownerCache, - }, nil -} - -func (p *PageClient) Validate() error { - ver, _, err := p.GiteaConfig.Client.ServerVersion() - p.logger.Info("Gitea Version ", zap.String("version", ver)) - if err != nil { - p.logger.Warn("Failed to get Gitea version", zap.Error(err)) - } - return nil -} diff --git a/pages/cname.go b/pages/cname.go deleted file mode 100644 index 576b9bf..0000000 --- a/pages/cname.go +++ /dev/null @@ -1,98 +0,0 @@ -package pages - -import ( - "encoding/json" - "fmt" - cmap "github.com/orcaman/concurrent-map/v2" - "os" - "strings" - "sync" -) - -var shared = cmap.New[PageDomain]() - -type CustomDomains struct { - /// 映射关系 - Alias *cmap.ConcurrentMap[string, PageDomain] `json:"alias,omitempty"` - /// 反向链接 - Reverse *cmap.ConcurrentMap[string, string] `json:"reverse,omitempty"` - /// 写锁 - Mutex sync.Mutex `json:"-"` - /// 文件落盘 - Local string `json:"-"` - // 是否全局共享 - Share bool `json:"-"` -} - -func (d *CustomDomains) Get(host string) (PageDomain, bool) { - get, b := d.Alias.Get(strings.ToLower(host)) - if !b && d.Share { - return shared.Get(strings.ToLower(host)) - } - return get, b -} - -func (d *CustomDomains) add(domain *PageDomain, aliases ...string) { - d.Mutex.Lock() - defer d.Mutex.Unlock() - for _, alias := range aliases { - key := strings.ToLower(domain.Key()) - alias = strings.ToLower(alias) - old, b := d.Reverse.Get(key) - if b { - // 移除旧的映射关系 - if d.Share { - shared.Remove(old) - } - d.Alias.Remove(old) - d.Reverse.Remove(key) - } - if d.Share { - shared.Set(alias, *domain) - } - d.Alias.Set(alias, *domain) - d.Reverse.Set(key, alias) - } - if d.Local != "" { - marshal, err := json.Marshal(d) - err = os.WriteFile(d.Local, marshal, 0644) - if err != nil { - fmt.Printf("%v\n", err) - } - } -} - -func NewCustomDomains(local string, share bool) (*CustomDomains, error) { - if share { - fmt.Printf("Global Alias Enabled.\n") - } - stat, err := os.Stat(local) - alias := cmap.New[PageDomain]() - reverse := cmap.New[string]() - result := &CustomDomains{ - Alias: &alias, - Reverse: &reverse, - Mutex: sync.Mutex{}, - Local: local, - Share: share, - } - fmt.Printf("Discover alias file :%s.\n", local) - if local != "" && err == nil && !stat.IsDir() { - bytes, err := os.ReadFile(local) - if err != nil { - return nil, err - } - err = json.Unmarshal(bytes, result) - fmt.Printf("Found %d Alias records.\n", result.Alias.Count()) - - if err != nil { - return nil, err - } - if share { - for k, v := range result.Alias.Items() { - shared.Set(k, v) - } - } - } - return result, nil -} diff --git a/pages/error.go b/pages/error.go deleted file mode 100644 index 59dc885..0000000 --- a/pages/error.go +++ /dev/null @@ -1,10 +0,0 @@ -package pages - -import "github.com/pkg/errors" - -var ( - // ErrorNotMatches 确认这不是 Gitea Pages 相关的域名 - ErrorNotMatches = errors.New("not matching") - ErrorNotFound = errors.New("not found") - ErrorInternal = errors.New("internal error") -) diff --git a/pages/failback.go b/pages/failback.go deleted file mode 100644 index a76a9da..0000000 --- a/pages/failback.go +++ /dev/null @@ -1,94 +0,0 @@ -package pages - -import ( - "embed" - "github.com/Masterminds/sprig/v3" - "github.com/pkg/errors" - "net/http" - "strconv" - "text/template" -) - -type ErrorMetadata struct { - StatusCode int - Request *http.Request - Error string -} - -var ( - //go:embed 40x.gohtml 50x.gohtml - embedPages embed.FS -) - -type ErrorPages struct { - errorPages map[string]*template.Template -} - -func newTemplate(key, text string) (*template.Template, error) { - return template.New(key).Funcs(sprig.TxtFuncMap()).Parse(text) -} -func NewErrorPages(pagesTmpl map[string]string) (*ErrorPages, error) { - pages := make(map[string]*template.Template) - for key, value := range pagesTmpl { - tmpl, err := newTemplate(key, value) - if err != nil { - return nil, err - } - pages[key] = tmpl - } - - if pages["40x"] == nil { - data, err := embedPages.ReadFile("40x.gohtml") - if err != nil { - return nil, err - } - pages["40x"], err = newTemplate("40x", string(data)) - if err != nil { - return nil, err - } - } - if pages["50x"] == nil { - data, err := embedPages.ReadFile("50x.gohtml") - if err != nil { - return nil, err - } - pages["50x"], err = newTemplate("50x", string(data)) - if err != nil { - return nil, err - } - } - return &ErrorPages{ - errorPages: pages, - }, nil -} - -func (p *ErrorPages) flushError(err error, request *http.Request, writer http.ResponseWriter) error { - var code = http.StatusInternalServerError - if errors.Is(err, ErrorNotMatches) { - // 跳过不匹配 - return err - } else if errors.Is(err, ErrorNotFound) { - code = http.StatusNotFound - } else { - code = http.StatusInternalServerError - } - var metadata = &ErrorMetadata{ - StatusCode: code, - Request: request, - Error: err.Error(), - } - codeStr := strconv.Itoa(code) - writer.Header().Add("Content-Type", "text/html;charset=utf-8") - writer.WriteHeader(code) - if result := p.errorPages[codeStr]; result != nil { - return result.Execute(writer, metadata) - } - switch { - case code >= 400 && code < 500: - return p.errorPages["40x"].Execute(writer, metadata) - case code >= 500: - return p.errorPages["50x"].Execute(writer, metadata) - default: - return p.errorPages["50x"].Execute(writer, metadata) - } -} diff --git a/pages/fake_resp.go b/pages/fake_resp.go deleted file mode 100644 index b225037..0000000 --- a/pages/fake_resp.go +++ /dev/null @@ -1,53 +0,0 @@ -package pages - -import ( - "fmt" - "mime" - "net/http" - "path/filepath" - "strconv" -) - -type FakeResponse struct { - *http.Response -} - -func (r *FakeResponse) Length(len int) { - r.ContentLength = int64(len) - r.Header.Set("Content-Length", strconv.Itoa(len)) -} - -func (r *FakeResponse) CacheModeIgnore() { - r.CacheMode("SKIP") -} -func (r *FakeResponse) CacheModeMiss() { - r.CacheMode("MISS") -} -func (r *FakeResponse) CacheModeHit() { - r.CacheMode("HIT") -} -func (r *FakeResponse) CacheMode(mode string) { - r.SetHeader("Pages-Server-Cache", mode) -} -func (r *FakeResponse) ContentTypeExt(path string) { - r.ContentType(mime.TypeByExtension(filepath.Ext(path))) -} -func (r *FakeResponse) ContentType(types string) { - r.Header.Set("Content-Type", types) -} -func (r *FakeResponse) ETag(tag string) { - r.Header.Set("ETag", fmt.Sprintf("\"%s\"", tag)) -} - -func NewFakeResponse() *FakeResponse { - return &FakeResponse{ - &http.Response{ - StatusCode: http.StatusOK, - Header: make(http.Header), - }, - } -} - -func (r *FakeResponse) SetHeader(key string, value string) { - r.Header.Set(key, value) -} diff --git a/pages/gitea.go b/pages/gitea.go deleted file mode 100644 index 04a3ded..0000000 --- a/pages/gitea.go +++ /dev/null @@ -1,85 +0,0 @@ -package pages - -import ( - "code.gitea.io/sdk/gitea" - "fmt" - "github.com/pkg/errors" - "go.uber.org/zap" - "io" - "net/http" - "net/url" -) - -type GiteaConfig struct { - Server string `json:"server"` - Token string `json:"token"` - Client *gitea.Client `json:"-"` - Logger *zap.Logger `json:"-"` - CustomHeaders map[string]string `json:"custom_headers"` - CacheMaxSize int `json:"max_cache_size"` -} - -func (c *GiteaConfig) FileExists(domain *PageDomain, path string) (bool, error) { - context, err := c.OpenFileContext(domain, path) - if context != nil { - defer context.Body.Close() - } - if errors.Is(err, ErrorNotFound) { - return false, nil - } else if err != nil { - return false, err - } - return true, nil -} - -func (c *GiteaConfig) ReadStringRepoFile(domain *PageDomain, path string) (string, error) { - data, err := c.ReadRepoFile(domain, path) - if err != nil { - return "", err - } - return string(data), nil -} - -func (c *GiteaConfig) ReadRepoFile(domain *PageDomain, path string) ([]byte, error) { - context, err := c.OpenFileContext(domain, path) - if err != nil { - return nil, err - } - defer context.Body.Close() - all, err := io.ReadAll(context.Body) - if err != nil { - return nil, err - } - return all, nil -} - -func (c *GiteaConfig) OpenFileContext(domain *PageDomain, path string) (*http.Response, error) { - var ( - giteaURL string - err error - ) - giteaURL, err = url.JoinPath(c.Server+"/api/v1/repos/", domain.Owner, domain.Repo, "media", path) - if err != nil { - return nil, err - } - giteaURL += "?ref=" + url.QueryEscape(domain.Branch) - req, err := http.NewRequest(http.MethodGet, giteaURL, nil) - if err != nil { - return nil, err - } - req.Header.Add("Authorization", "token "+c.Token) - resp, err := http.DefaultClient.Do(req) - if err != nil { - return nil, errors.Wrap(err, "") - } - switch resp.StatusCode { - case http.StatusForbidden: - return nil, errors.Wrap(ErrorNotFound, "domain file not forbidden") - case http.StatusNotFound: - return nil, errors.Wrap(ErrorNotFound, fmt.Sprintf("domain file not found: %s", path)) - case http.StatusOK: - default: - return nil, errors.Wrap(ErrorInternal, fmt.Sprintf("unexpected status code '%d'", resp.StatusCode)) - } - return resp, nil -} diff --git a/pages/middle.go b/pages/middle.go deleted file mode 100644 index ba8ad0b..0000000 --- a/pages/middle.go +++ /dev/null @@ -1,17 +0,0 @@ -package pages - -import "time" - -type MiddlewareConfig struct { - Server string `json:"server"` - Token string `json:"token"` - Domain string `json:"domain"` - Alias string `json:"alias"` - CacheRefresh time.Duration `json:"cache_refresh"` - CacheTimeout time.Duration `json:"cache_timeout"` - ErrorPages map[string]string `json:"errors"` - CustomHeaders map[string]string `json:"custom_headers"` - AutoRedirect *AutoRedirect `json:"redirect"` - SharedAlias bool `json:"shared_alias"` - CacheMaxSize int `json:"cache_max_size"` -} diff --git a/pages/page.go b/pages/page.go deleted file mode 100644 index 8050630..0000000 --- a/pages/page.go +++ /dev/null @@ -1,21 +0,0 @@ -package pages - -import "fmt" - -type PageDomain struct { - Owner string `json:"owner"` - Repo string `json:"repo"` - Branch string `json:"branch"` -} - -func NewPageDomain(owner string, repo string, branch string) *PageDomain { - return &PageDomain{ - owner, - repo, - branch, - } -} - -func (p *PageDomain) Key() string { - return fmt.Sprintf("%s|%s|%s", p.Owner, p.Repo, p.Branch) -} diff --git a/pages/parser.go b/pages/parser.go deleted file mode 100644 index d29d9a4..0000000 --- a/pages/parser.go +++ /dev/null @@ -1,70 +0,0 @@ -package pages - -import ( - "fmt" - "github.com/pkg/errors" - "net/http" - "strings" -) - -func (p *PageClient) parseDomain(request *http.Request) (*PageDomain, string, error) { - if strings.Contains(request.Host, "]") { - //跳过 ipv6 address 直接访问, 因为仅支持域名的方式 - return nil, "", ErrorNotMatches - } - host := strings.Split(request.Host, ":")[0] - filePath := request.URL.Path - pathTrim := strings.Split(strings.Trim(filePath, "/"), "/") - repo := pathTrim[0] - // 处理 scheme://domain/path 的情况 - if !strings.HasPrefix(filePath, fmt.Sprintf("/%s/", repo)) { - repo = "" - } - if strings.HasSuffix(host, p.BaseDomain) { - child := strings.Split(strings.TrimSuffix(host, p.BaseDomain), ".") - result := NewPageDomain( - child[len(child)-1], - repo, - "gh-pages", - ) - // 处于使用默认 Domain 下 - config, err := p.OwnerCache.GetOwnerConfig(p.GiteaConfig, result.Owner) - if err != nil { - return nil, "", err - } - ownerRepoName := result.Owner + p.BaseDomain - if result.Repo == "" && config.Exists(ownerRepoName) { - // 推导为默认仓库 - result.Repo = ownerRepoName - return result, filePath, nil - } else if result.Repo == "" || !config.Exists(result.Repo) { - if config.Exists(ownerRepoName) { - result.Repo = ownerRepoName - return result, filePath, nil - } - // 未指定 repo 或者 repo 不存在,跳过 - return nil, "", errors.Wrap(ErrorNotFound, result.Repo+" not found") - } - // 存在子目录且仓库存在 - pathTrim = pathTrim[1:] - path := "" - if strings.HasSuffix(filePath, "/") { - path = "/" + strings.Join(pathTrim, "/") + "/" - } else { - path = "/" + strings.Join(pathTrim, "/") - } - path = strings.ReplaceAll(path, "//", "/") - path = strings.ReplaceAll(path, "//", "/") - if path == "" { - path = "/" - } - return result, path, nil - } else { - get, exists := p.DomainAlias.Get(host) - if exists { - return &get, filePath, nil - } else { - return nil, "", errors.Wrap(ErrorNotFound, "") - } - } -} diff --git a/pages/route.go b/pages/route.go deleted file mode 100644 index 616e819..0000000 --- a/pages/route.go +++ /dev/null @@ -1,59 +0,0 @@ -package pages - -import ( - "fmt" - "github.com/pkg/errors" - "go.uber.org/zap" - "net/http" - "runtime" - "strings" -) - -func (p *PageClient) Route(writer http.ResponseWriter, request *http.Request) error { - defer func() error { - //放在匿名函数里,err捕获到错误信息,并且输出 - err := recover() - if err != nil { - p.logger.Error("recovered from panic", zap.Any("err", err)) - var buf [4096]byte - n := runtime.Stack(buf[:], false) - println(string(buf[:n])) - return p.ErrorPages.flushError(errors.New(fmt.Sprintf("%v", err)), request, writer) - } - return nil - }() - err := p.RouteExists(writer, request) - if err != nil { - p.logger.Debug("route exists error", zap.String("host", request.Host), - zap.String("path", request.RequestURI), zap.Error(err)) - return p.ErrorPages.flushError(err, request, writer) - } - return err -} - -func (p *PageClient) RouteExists(writer http.ResponseWriter, request *http.Request) error { - domain, filePath, err := p.parseDomain(request) - if err != nil { - return err - } - config, cache, err := p.DomainCache.FetchRepo(p.GiteaConfig, domain) - if err != nil { - return err - } - if !config.Exists { - return ErrorNotFound - } - if !cache && len(config.CNAME) > 0 { - p.logger.Info("Add CNAME link.", zap.Any("CNAME", config.CNAME)) - p.DomainAlias.add(domain, config.CNAME...) - } - // 跳过 30x 重定向 - if p.AutoRedirect.Enabled && - len(config.CNAME) > 0 && - strings.HasPrefix(request.Host, domain.Owner+p.BaseDomain) { - http.Redirect(writer, request, p.AutoRedirect.Scheme+"://"+config.CNAME[0], p.AutoRedirect.Code) - return nil - } - _, err = config.Copy(p.GiteaConfig, filePath, writer, request) - return err -}