fork from prologic/pages-server
This commit is contained in:
parent
9d86fd33c6
commit
839a429820
33 changed files with 865 additions and 2482 deletions
17
.dockerfiles/entrypoint.sh
Normal file
17
.dockerfiles/entrypoint.sh
Normal file
|
@ -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
|
6
.dockerignore
Normal file
6
.dockerignore
Normal file
|
@ -0,0 +1,6 @@
|
|||
*~
|
||||
*.bak
|
||||
**/.envrc
|
||||
**/.DS_store
|
||||
|
||||
/pages-server
|
21
.gitea/workflows/build.yml
Normal file
21
.gitea/workflows/build.yml
Normal file
|
@ -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
|
10
.gitignore
vendored
10
.gitignore
vendored
|
@ -1,4 +1,6 @@
|
|||
/caddy
|
||||
/.idea
|
||||
*.iml
|
||||
/Caddyfile.local
|
||||
*~
|
||||
*.bak
|
||||
**/.envrc
|
||||
**/.DS_store
|
||||
|
||||
/pages-server
|
||||
|
|
47
Caddyfile
47
Caddyfile
|
@ -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
|
||||
}
|
66
Dockerfile
66
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
|
||||
# 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"]
|
215
LICENSE
215
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.
|
||||
|
|
91
Makefile
91
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 .
|
||||
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
|
||||
|
|
91
README.md
91
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 `*.<domain>`
|
||||
- Option 1: Repo with `gitea-pages` branch + `gitea-pages` topic => `https://<owner>.<domain>/<repo>/<path>`
|
||||
- Option 2: Repo of the form `<subdomain>.<domain>` with `gitea-pages` branch and gitea-pages topic => `https://<subdomain>.<domain>`
|
||||
|
||||
此处需要用到 `xcaddy` 工具,使用如下命令生成 Caddy 执行文件,
|
||||
如果 `xcaddy` 不存在,需先前往 [caddyserver/xcaddy](https://github.com/caddyserver/xcaddy/releases) 安装 `xcaddy`,
|
||||
同时安装好 Golang 1.22
|
||||
Where `<domain>` 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>.<domain>/<repo>` => `owner/repo`
|
||||
- Proxies `<subdomain>.<domain>` => `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` 配置的域名,则需要先访问仓库对应的 `<owner>.example.com/<repo>` 域名, 此操作只需完成一次。
|
||||
|
||||
**注意**: 需要仓库存在 `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).
|
||||
|
|
67
README_en.md
67
README_en.md
|
@ -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 `<owner>.example.com/<repo>` 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)
|
246
caddyfile.go
246
caddyfile.go
|
@ -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)
|
||||
)
|
32
docker-stack.yml
Normal file
32
docker-stack.yml
Normal file
|
@ -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
|
180
gitea/frontmatter.go
Normal file
180
gitea/frontmatter.go
Normal file
|
@ -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
|
||||
}
|
93
gitea/fs.go
Normal file
93
gitea/fs.go
Normal file
|
@ -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
|
||||
}
|
218
gitea/gitea.go
Normal file
218
gitea/gitea.go
Normal file
|
@ -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("<!DOCTYPE html>\n<html>\n<body>\n<h1>"), []byte(title)...)
|
||||
res = append(res, []byte("</h1>")...)
|
||||
res = append(res, html...)
|
||||
res = append(res, []byte("</body></html>")...)
|
||||
|
||||
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:], "/")
|
||||
}
|
||||
}
|
132
go.mod
132
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
|
||||
)
|
||||
|
|
622
go.sum
622
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=
|
||||
|
|
68
main.go
Normal file
68
main.go
Normal file
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport"
|
||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>404 Not Found</title>
|
||||
</head>
|
||||
<Body>
|
||||
<div style="text-align: center;"><h1>404 Not Found</h1></div>
|
||||
<hr>
|
||||
<div style="text-align: center;">Gitea Pages</div>
|
||||
</Body>
|
||||
</html>
|
|
@ -1,15 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport"
|
||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>500 Internal Error</title>
|
||||
</head>
|
||||
<Body>
|
||||
<div style="text-align: center;"><h1>500 Internal Error</h1></div>
|
||||
<hr>
|
||||
<div style="text-align: center;">Gitea Pages</div>
|
||||
</Body>
|
||||
</html>
|
19
pages/buf.go
19
pages/buf.go
|
@ -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
|
||||
}
|
|
@ -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() }
|
||||
}
|
|
@ -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)]
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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")
|
||||
)
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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"`
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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, "")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue