Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f148240bcf | ||
|
|
f914931bc9 | ||
|
|
8c1033634d | ||
|
|
781b79f529 | ||
|
|
ad91703492 | ||
|
|
a007c81e9a | ||
|
|
39bffe3389 | ||
|
|
3f2767b28b | ||
|
|
312c6e685a | ||
|
|
d2b6ab75b7 | ||
|
|
dc16294b3d | ||
|
|
77dfcef168 | ||
|
|
30ef5841d6 | ||
|
|
217ba85ff8 | ||
|
|
71e2555391 | ||
|
|
f036eb1cf2 | ||
|
|
1347066549 | ||
|
|
7fc149f67d | ||
|
|
dfba5ee638 | ||
|
|
9ba79f996f | ||
|
|
cd85000908 | ||
|
|
995349ab3e | ||
|
|
4fa8031318 | ||
|
|
3f45bb1629 | ||
|
|
0e139e6284 | ||
|
|
82dbfc6de3 | ||
|
|
9b2937d601 |
45
README.md
45
README.md
@@ -1,4 +1,4 @@
|
||||
[中文](README.md) | [English](README_EN.md)
|
||||
[中文](README.md) | [English](README_EN.md)
|
||||
|
||||
# 🔒Certimate
|
||||
|
||||
@@ -18,13 +18,8 @@ Certimate 就是为了解决上述问题而产生的,它具有以下特点:
|
||||
* [Why Certimate?](https://docs.certimate.me/blog/why-certimate)
|
||||
* [域名变量及部署授权组介绍](https://docs.certimate.me/blog/multi-deployer)
|
||||
|
||||
|
||||
Certimate 旨在为用户提供一个安全、简便的 SSL 证书管理解决方案。使用文档请访问[https://docs.certimate.me](https://docs.certimate.me)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 一、安装
|
||||
|
||||
安装 Certimate 非常简单,你可以选择以下方式之一进行安装:
|
||||
@@ -37,10 +32,14 @@ Certimate 旨在为用户提供一个安全、简便的 SSL 证书管理解决
|
||||
./certimate serve
|
||||
```
|
||||
|
||||
或运行以下命令自动给 Certimate 自身添加证书
|
||||
```bash
|
||||
./certimate serve 你的域名
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> MacOS 在执行二进制文件时会提示:无法打开“certimate”,因为Apple无法检查其是否包含恶意软件。可在系统设置> 隐私与安全性> 安全性 中点击 "仍然允许",然后再次尝试执行二进制文件。
|
||||
|
||||
|
||||
### 2. Docker 安装
|
||||
|
||||
```bash
|
||||
@@ -58,7 +57,6 @@ go mod vendor
|
||||
go run main.go serve
|
||||
```
|
||||
|
||||
|
||||
## 二、使用
|
||||
|
||||
执行完上述安装操作后,在浏览器中访问 `http://127.0.0.1:8090` 即可访问 Certimate 管理页面。
|
||||
@@ -72,17 +70,14 @@ go run main.go serve
|
||||
|
||||
## 三、支持的服务商列表
|
||||
|
||||
| 服务商 | 是否域名服务商 | 是否部署服务 | 备注 |
|
||||
|------|------|-----|------|
|
||||
| 阿里云| 是 | 是 | 支持阿里云注册的域名,支持部署到阿里云 CDN,OSS |
|
||||
| 腾讯云| 是 | 是 | 支持腾讯云注册的域名,支持部署到腾讯云 CDN |
|
||||
| 七牛云| 否 | 是 | 七牛云没有注册域名服务,支持部署到七牛云 CDN |
|
||||
|CloudFlare| 是 | 否 | 支持 CloudFlare 注册的域名,CloudFlare 服务自带SSL证书 |
|
||||
|SSH| 否 | 是 | 支持部署到 SSH 服务器 |
|
||||
|WEBHOOK| 否 | 是 | 支持回调到 WEBHOOK |
|
||||
|
||||
|
||||
|
||||
| 服务商 | 是否域名服务商 | 是否部署服务 | 备注 |
|
||||
| ---------- | -------------- | ------------ | ------------------------------------------------------ |
|
||||
| 阿里云 | 是 | 是 | 支持阿里云注册的域名,支持部署到阿里云 CDN,OSS |
|
||||
| 腾讯云 | 是 | 是 | 支持腾讯云注册的域名,支持部署到腾讯云 CDN |
|
||||
| 七牛云 | 否 | 是 | 七牛云没有注册域名服务,支持部署到七牛云 CDN |
|
||||
| CloudFlare | 是 | 否 | 支持 CloudFlare 注册的域名,CloudFlare 服务自带SSL证书 |
|
||||
| SSH | 否 | 是 | 支持部署到 SSH 服务器 |
|
||||
| WEBHOOK | 否 | 是 | 支持回调到 WEBHOOK |
|
||||
|
||||
## 四、系统截图
|
||||
|
||||
@@ -96,7 +91,6 @@ go run main.go serve
|
||||
|
||||

|
||||
|
||||
|
||||
## 五、概念
|
||||
|
||||
Certimate 的工作流程如下:
|
||||
@@ -140,7 +134,6 @@ Certimate 申请证书后,会自动将证书部署到你指定的目标上,
|
||||
|
||||
## 六、常见问题
|
||||
|
||||
|
||||
Q: 提供saas服务吗?
|
||||
|
||||
> A: 不提供,目前仅支持self-hosted(私有部署)。
|
||||
@@ -153,8 +146,6 @@ Q: 自动续期证书?
|
||||
|
||||
> A: 已经申请的证书会在过期前10天自动续期。每天会检查一次证书是否快要过期,快要过期时会自动重新申请证书并部署到目标服务上。
|
||||
|
||||
|
||||
|
||||
## 七、贡献
|
||||
|
||||
Certimate 是一个免费且开源的项目,采用 [MIT 开源协议](LICENSE.md)。你可以使用它做任何你想做的事,甚至把它当作一个付费服务提供给用户。
|
||||
@@ -168,8 +159,10 @@ Certimate 是一个免费且开源的项目,采用 [MIT 开源协议](LICENSE.
|
||||
|
||||
## 八、加入社区
|
||||
|
||||
* [Telegram-a new era of messaging](https://t.me/+ZXphsppxUg41YmVl)
|
||||
* [Telegram-a new era of messaging](https://t.me/+ZXphsppxUg41YmVl)
|
||||
* 微信群聊(超200人需邀请入群,可先加作者好友)
|
||||
|
||||
* 微信群聊
|
||||
<img src="https://i.imgur.com/8xwsLTA.png" width="400"/>
|
||||
|
||||
<img src="https://i.imgur.com/zSHEoIm.png" width="400"/>
|
||||
## 九、Star History
|
||||
[](https://starchart.cc/usual2970/certimate)
|
||||
|
||||
49
README_EN.md
49
README_EN.md
@@ -1,10 +1,9 @@
|
||||
[中文](README.md) | [English](README_EN.md)
|
||||
[中文](README.md) | [English](README_EN.md)
|
||||
|
||||
# 🔒Certimate
|
||||
|
||||
For individuals managing personal projects or those responsible for IT operations in small businesses who need to manage multiple domain names, applying for certificates manually comes with several drawbacks:
|
||||
|
||||
|
||||
1. 😱Troublesome: Applying for and deploying certificates isn’t difficult, but it can be quite a hassle, especially when managing multiple domains.
|
||||
2. 😭Easily forgotten: The current free certificate has a validity period of only 90 days, requiring regular renewal operations. This increases the workload and makes it easy to forget, which can result in the website becoming inaccessible.
|
||||
|
||||
@@ -19,30 +18,29 @@ Related articles:
|
||||
* [Why Certimate?](https://docs.certimate.me/blog/why-certimate)
|
||||
* [Introduction to Domain Variables and Deployment Authorization Groups](https://docs.certimate.me/blog/multi-deployer)
|
||||
|
||||
|
||||
Certimate aims to provide users with a secure and user-friendly SSL certificate management solution. For usage documentation, please visit.[https://docs.certimate.me](https://docs.certimate.me)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
Installing Certimate is very simple, you can choose one of the following methods for installation:
|
||||
|
||||
### 1. Binary File
|
||||
|
||||
|
||||
You can download the precompiled binary files directly from the [Releases page](https://github.com/usual2970/certimate/releases), and after extracting them, execute:
|
||||
|
||||
```bash
|
||||
./certimate serve
|
||||
```
|
||||
|
||||
Or run the following command to automatically add a certificate to Certimate itself.
|
||||
|
||||
```bash
|
||||
./certimate serve yourDomain
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> When executing the binary file on macOS, you may see a prompt saying: “Cannot open ‘certimate’ because Apple cannot check it for malicious software.” You can go to System Preferences > Security & Privacy > General, then click “Allow Anyway,” and try executing the binary file again.
|
||||
|
||||
|
||||
### 2. Docker Installation
|
||||
|
||||
```bash
|
||||
@@ -60,7 +58,6 @@ go mod vendor
|
||||
go run main.go serve
|
||||
```
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
After completing the installation steps above, you can access the Certimate management page by visiting http://127.0.0.1:8090 in your browser.
|
||||
@@ -74,19 +71,16 @@ password:1234567890
|
||||
|
||||
## List of Supported Providers
|
||||
|
||||
| Provider | Domain Registrar | Deployment Service | Remarks |
|
||||
| ------------- | ---------------- | ------------------ | ------------------------------------------------------------------------------------------------- |
|
||||
| Alibaba Cloud | Yes | Yes | Supports domains registered with Alibaba Cloud; supports deployment to Alibaba Cloud CDN and OSS. |
|
||||
| Tencent Cloud | Yes | Yes | Supports domains registered with Tencent Cloud; supports deployment to Tencent Cloud CDN. |
|
||||
| Qiniu Cloud | No | Yes | Qiniu Cloud does not offer domain registration services; supports deployment to Qiniu Cloud CDN. |
|
||||
| Cloudflare | Yes | No | Supports domains registered with Cloudflare; Cloudflare services come with SSL certificates. |
|
||||
| SSH | No | Yes | Supports deployment to SSH servers. |
|
||||
| WEBHOOK | No | Yes | Supports callbacks to WEBHOOK. |
|
||||
|
||||
| Provider | Domain Registrar | Deployment Service | Remarks |
|
||||
|--------------|------------------|--------------------|------------------------------------------------------|
|
||||
| Alibaba Cloud| Yes | Yes | Supports domains registered with Alibaba Cloud; supports deployment to Alibaba Cloud CDN and OSS. |
|
||||
| Tencent Cloud| Yes | Yes | Supports domains registered with Tencent Cloud; supports deployment to Tencent Cloud CDN. |
|
||||
| Qiniu Cloud | No | Yes | Qiniu Cloud does not offer domain registration services; supports deployment to Qiniu Cloud CDN. |
|
||||
| Cloudflare | Yes | No | Supports domains registered with Cloudflare; Cloudflare services come with SSL certificates. |
|
||||
| SSH | No | Yes | Supports deployment to SSH servers. |
|
||||
| WEBHOOK | No | Yes | Supports callbacks to WEBHOOK. |
|
||||
|
||||
|
||||
|
||||
## Screenshots
|
||||
## Screenshots
|
||||
|
||||

|
||||
|
||||
@@ -98,7 +92,6 @@ password:1234567890
|
||||
|
||||

|
||||
|
||||
|
||||
## Concepts
|
||||
|
||||
The workflow of Certimate is as follows:
|
||||
@@ -140,8 +133,7 @@ After Certimate applies for the certificate, it will automatically deploy the ce
|
||||
|
||||
The authorization information for the deployment service provider is the same as that for the DNS provider, with the distinction that the DNS provider's authorization information is used to prove that the domain belongs to you, while the deployment service provider's authorization information is used to provide authorization for the certificate deployment.
|
||||
|
||||
## FAQ
|
||||
|
||||
## FAQ
|
||||
|
||||
Q: Do you provide SaaS services?
|
||||
|
||||
@@ -155,8 +147,6 @@ Q: Automatic Certificate Renewal?
|
||||
|
||||
> A: Certificates that have already been issued will be automatically renewed 10 days before expiration. The system checks once a day to see if any certificates are nearing expiration, and if so, it will automatically reapply for the certificate and deploy it to the target service.
|
||||
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
Certimate is a free and open-source project, licensed under the [MIT License](LICENSE.md). You can use it for anything you want, even offering it as a paid service to users.
|
||||
@@ -170,8 +160,7 @@ Support for more service providers, UI enhancements, bug fixes, and documentatio
|
||||
|
||||
## Join the Community
|
||||
|
||||
* [Telegram-a new era of messaging](https://t.me/+ZXphsppxUg41YmVl)
|
||||
|
||||
* Wechat Group
|
||||
* [Telegram-a new era of messaging](https://t.me/+ZXphsppxUg41YmVl)
|
||||
* Wechat Group
|
||||
|
||||
<img src="https://i.imgur.com/zSHEoIm.png" width="400"/>
|
||||
|
||||
89
go.mod
89
go.mod
@@ -1,8 +1,8 @@
|
||||
module certimate
|
||||
|
||||
go 1.22
|
||||
go 1.22.0
|
||||
|
||||
toolchain go1.22.5
|
||||
toolchain go1.23.2
|
||||
|
||||
require (
|
||||
github.com/alibabacloud-go/cas-20200407/v2 v2.3.0
|
||||
@@ -10,7 +10,7 @@ require (
|
||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.9
|
||||
github.com/alibabacloud-go/tea v1.2.2
|
||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.6
|
||||
github.com/go-acme/lego/v4 v4.17.4
|
||||
github.com/go-acme/lego/v4 v4.19.2
|
||||
github.com/gojek/heimdall/v7 v7.0.3
|
||||
github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61
|
||||
github.com/nikoksr/notify v1.0.0
|
||||
@@ -18,9 +18,10 @@ require (
|
||||
github.com/pocketbase/dbx v1.10.1
|
||||
github.com/pocketbase/pocketbase v0.22.18
|
||||
github.com/qiniu/go-sdk/v7 v7.22.0
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.992
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1017
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1017
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.992
|
||||
golang.org/x/crypto v0.26.0
|
||||
golang.org/x/crypto v0.27.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -30,8 +31,10 @@ require (
|
||||
github.com/alibabacloud-go/tea-oss-utils v1.1.0 // indirect
|
||||
github.com/blinkbean/dingtalk v1.1.3 // indirect
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible // indirect
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.114 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
|
||||
go.mongodb.org/mongo-driver v1.12.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -44,39 +47,39 @@ require (
|
||||
github.com/alibabacloud-go/openapi-util v0.1.0 // indirect
|
||||
github.com/alibabacloud-go/tea-utils v1.4.5 // indirect
|
||||
github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.62.712 // indirect
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.63.15 // indirect
|
||||
github.com/aliyun/credentials-go v1.3.1 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.30.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.27 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.27 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.30.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.33 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.32 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.58.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect
|
||||
github.com/aws/smithy-go v1.20.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.19 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.61.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.22.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.30.7 // indirect
|
||||
github.com/aws/smithy-go v1.20.4 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/clbanning/mxj/v2 v2.5.6 // indirect
|
||||
github.com/cloudflare/cloudflare-go v0.97.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/cloudflare/cloudflare-go v0.104.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/disintegration/imaging v1.6.2 // indirect
|
||||
github.com/domodwyer/mailyak/v3 v3.6.2 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/fatih/color v1.17.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.4 // indirect
|
||||
github.com/ganigeorgiev/fexpr v0.4.1 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.2 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.4 // indirect
|
||||
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect
|
||||
github.com/goccy/go-json v0.10.3 // indirect
|
||||
github.com/gojek/valkyrie v0.0.0-20180215180059-6aee720afcdf // indirect
|
||||
@@ -85,8 +88,6 @@ require (
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.13.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
@@ -97,39 +98,39 @@ require (
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.22 // indirect
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
||||
github.com/miekg/dns v1.1.59 // indirect
|
||||
github.com/miekg/dns v1.1.62 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
github.com/nrdcg/namesilo v0.2.1 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/spf13/cobra v1.8.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
github.com/stretchr/testify v1.9.0 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.898 // indirect
|
||||
github.com/tjfoc/gmsm v1.3.2 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1002 // indirect
|
||||
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
gocloud.dev v0.37.0 // indirect
|
||||
golang.org/x/image v0.18.0 // indirect
|
||||
golang.org/x/mod v0.18.0 // indirect
|
||||
golang.org/x/net v0.27.0 // indirect
|
||||
golang.org/x/oauth2 v0.21.0 // indirect
|
||||
golang.org/x/mod v0.21.0 // indirect
|
||||
golang.org/x/net v0.29.0 // indirect
|
||||
golang.org/x/oauth2 v0.23.0 // indirect
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
golang.org/x/sys v0.24.0 // indirect
|
||||
golang.org/x/term v0.23.0 // indirect
|
||||
golang.org/x/text v0.17.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/tools v0.22.0 // indirect
|
||||
golang.org/x/sys v0.25.0 // indirect
|
||||
golang.org/x/term v0.24.0 // indirect
|
||||
golang.org/x/text v0.18.0 // indirect
|
||||
golang.org/x/time v0.6.0 // indirect
|
||||
golang.org/x/tools v0.25.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect
|
||||
google.golang.org/api v0.189.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a // indirect
|
||||
google.golang.org/grpc v1.65.0 // indirect
|
||||
google.golang.org/api v0.197.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
||||
google.golang.org/grpc v1.66.1 // indirect
|
||||
google.golang.org/protobuf v1.34.2 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
||||
247
go.sum
247
go.sum
@@ -1,13 +1,13 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.115.0 h1:CnFSK6Xo3lDYRoBKEcAtia6VSC837/ZkJuRduSFnr14=
|
||||
cloud.google.com/go v0.115.0/go.mod h1:8jIM5vVgoAEoiVxQ/O4BFTfHqulPZgs/ufEzMcFMdWU=
|
||||
cloud.google.com/go/auth v0.7.2 h1:uiha352VrCDMXg+yoBtaD0tUF4Kv9vrtrWPYXwutnDE=
|
||||
cloud.google.com/go/auth v0.7.2/go.mod h1:VEc4p5NNxycWQTMQEDQF0bd6aTMb6VgYDXEwiJJQAbs=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.3 h1:MlxF+Pd3OmSudg/b1yZ5lJwoXCEaeedAguodky1PcKI=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.3/go.mod h1:tMQXOfZzFuNuUxOypHlQEXgdfX5cuhwU+ffUuXRJE8I=
|
||||
cloud.google.com/go v0.115.1 h1:Jo0SM9cQnSkYfp44+v+NQXHpcHqlnRJk2qxh6yvxxxQ=
|
||||
cloud.google.com/go v0.115.1/go.mod h1:DuujITeaufu3gL68/lOFIirVNJwQeyf5UXyi+Wbgknc=
|
||||
cloud.google.com/go/auth v0.9.3 h1:VOEUIAADkkLtyfr3BLa3R8Ed/j6w1jTBmARx+wb5w5U=
|
||||
cloud.google.com/go/auth v0.9.3/go.mod h1:7z6VY+7h3KUdRov5F1i8NDP5ZzWKYmEPO842BgCsmTk=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc=
|
||||
cloud.google.com/go/compute v1.25.0 h1:H1/4SqSUhjPFE7L5ddzHOfY2bCAvjwNRZPNl6Ni5oYU=
|
||||
cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY=
|
||||
cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY=
|
||||
cloud.google.com/go/compute/metadata v0.5.1 h1:NM6oZeZNlYjiwYje+sYFjEpP0Q0zCan1bmQW/KmIrGs=
|
||||
cloud.google.com/go/compute/metadata v0.5.1/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k=
|
||||
cloud.google.com/go/iam v1.1.11 h1:0mQ8UKSfdHLut6pH9FM3bI55KWR46ketn0PuXleDyxw=
|
||||
cloud.google.com/go/iam v1.1.11/go.mod h1:biXoiLWYIKntto2joP+62sd9uW5EpkZmKIvfNcTWlnQ=
|
||||
cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs=
|
||||
@@ -80,8 +80,8 @@ github.com/alibabacloud-go/tea-xml v1.1.1/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCE
|
||||
github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
|
||||
github.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzYtqw7dgt0=
|
||||
github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.62.712 h1:lM7JnA9dEdDFH9XOgRNQMDTQnOjlLkDTNA7c0aWTQ30=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.62.712/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.63.15 h1:r2uwBUQhLhcPzaWz9tRJqc8MjYwHb+oF2+Q6467BF14=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.63.15/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
|
||||
github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=
|
||||
github.com/aliyun/credentials-go v1.3.1 h1:uq/0v7kWrxmoLGpqjx7vtQ/s03f0zR//0br/xWDTE28=
|
||||
github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0=
|
||||
@@ -90,44 +90,44 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3d
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/aws/aws-sdk-go v1.51.11 h1:El5VypsMIz7sFwAAj/j06JX9UGs4KAbAIEaZ57bNY4s=
|
||||
github.com/aws/aws-sdk-go v1.51.11/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
|
||||
github.com/aws/aws-sdk-go-v2 v1.30.3 h1:jUeBtG0Ih+ZIFH0F4UkmL9w3cSpaMv9tYYDbzILP8dY=
|
||||
github.com/aws/aws-sdk-go-v2 v1.30.3/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 h1:tW1/Rkad38LA15X4UQtjXZXNKsCgkshC3EbmcUmghTg=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3/go.mod h1:UbnqO+zjqk3uIt9yCACHJ9IVNhyhOCnYk8yA19SAWrM=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.27 h1:HdqgGt1OAP0HkEDDShEl0oSYa9ZZBSOmKpdpsDMdO90=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.27/go.mod h1:MVYamCg76dFNINkZFu4n4RjDixhVr51HLj4ErWzrVwg=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.27 h1:2raNba6gr2IfA0eqqiP2XiQ0UVOpGPgDSi0I9iAP+UI=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.27/go.mod h1:gniiwbGahQByxan6YjQUMcW4Aov6bLC3m+evgcoN4r4=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 h1:KreluoV8FZDEtI6Co2xuNk/UqI9iwMrOx/87PBNIKqw=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11/go.mod h1:SeSUYBLsMYFoRvHE0Tjvn7kbxaUhl75CJi1sbfhMxkU=
|
||||
github.com/aws/aws-sdk-go-v2 v1.30.5 h1:mWSRTwQAb0aLE17dSzztCVJWI9+cRMgqebndjwDyK0g=
|
||||
github.com/aws/aws-sdk-go-v2 v1.30.5/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4 h1:70PVAiL15/aBMh5LThwgXdSQorVr91L127ttckI9QQU=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4/go.mod h1:/MQxMqci8tlqDH+pjmoLu1i0tbWCUP1hhyMRuFxpQCw=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.33 h1:Nof9o/MsmH4oa0s2q9a0k7tMz5x/Yj5k06lDODWz3BU=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.33/go.mod h1:kEqdYzRb8dd8Sy2pOdEbExTTF5v7ozEXX0McgPE7xks=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.32 h1:7Cxhp/BnT2RcGy4VisJ9miUPecY+lyE9I8JvcZofn9I=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.32/go.mod h1:P5/QMF3/DCHbXGEGkdbilXHsyTBX5D3HSwcrSc9p20I=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13 h1:pfQ2sqNpMVK6xz2RbqLEL0GH87JOwSxPV2rzm8Zsb74=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13/go.mod h1:NG7RXPUlqfsCLLFfi0+IpKN4sCB9D9fw/qTaSB+xRoU=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.8 h1:u1KOU1S15ufyZqmH/rA3POkiRH6EcDANHj2xHRzq+zc=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.8/go.mod h1:WPv2FRnkIOoDv/8j2gSUsI4qDc7392w5anFB/I89GZ8=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 h1:SoNJ4RlFEQEbtDcCEt+QG56MY4fm4W8rYirAmq+/DdU=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15/go.mod h1:U9ke74k1n2bf+RIgoX1SXFed1HLs51OgUSs+Ph0KJP8=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 h1:C6WHdGnTDIYETAm5iErQUiVNsclNx9qbJVPIt03B6bI=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15/go.mod h1:ZQLZqhcu+JhSrA9/NXRm8SkDvsycE+JkV3WGY41e+IM=
|
||||
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/internal/v4a v1.3.15 h1:Z5r7SycxmSllHYmaAZPpmN8GviDrSGhMS6bldqtXZPw=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.15/go.mod h1:CetW7bDE00QoGEmPUoZuRog07SGVAUVW6LFpNP0YfIg=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 h1:dT3MqvGhSoaIhRseqw2I0yH81l7wiR2vjs57O51EAm8=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3/go.mod h1:GlAeCkHwugxdHaueRr4nhPuY+WW+gR8UjlcqzPr1SPI=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.17 h1:YPYe6ZmvUfDDDELqEKtAd6bo8zxhkm+XEFEzQisqUIE=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.17/go.mod h1:oBtcnYua/CgzCWYN7NZ5j7PotFDaFSUjCYVTtfyn7vw=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 h1:HGErhhrxZlQ044RiM+WdoZxp0p+EGM62y3L6pwA4olE=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17/go.mod h1:RkZEx4l0EHYDJpWppMJ3nD9wZJAa8/0lq9aVC+r2UII=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.15 h1:246A4lSTXWJw/rmlQI+TT2OcqeDMKBdyjEQrafMaQdA=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.15/go.mod h1:haVfg3761/WF7YPuJOER2MP0k4UAXyHaLclKXB6usDg=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.58.2 h1:sZXIzO38GZOU+O0C+INqbH7C2yALwfMWpd64tONS/NE=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.58.2/go.mod h1:Lcxzg5rojyVPU/0eFwLtcyTaek/6Mtic5B1gJo7e/zE=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 h1:BXx0ZIxvrJdSgSvKTZ+yRBeSqqgPM89VPlulEcl37tM=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.22.4/go.mod h1:ooyCOXjvJEsUw7x+ZDHeISPMhtwI3ZCB7ggFMcFfWLU=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 h1:yiwVzJW2ZxZTurVbYWA7QOrAaCYQR72t0wrSBfoesUE=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4/go.mod h1:0oxfLkpz3rQ/CHlx5hB7H69YUpFiI1tql6Q6Ne+1bCw=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 h1:ZsDKRLXGWHk8WdtyYMoGNO7bTudrvuKpDKgMVRlepGE=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.30.3/go.mod h1:zwySh8fpFyXp9yOr/KVzxOl8SRqgf/IDw5aUt9UKFcQ=
|
||||
github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE=
|
||||
github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17 h1:pI7Bzt0BJtYA0N/JEC6B8fJ4RBrEMi1LBrkMdFYNSnQ=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17/go.mod h1:Dh5zzJYMtxfIjYW+/evjQ8uj2OyR/ve2KROHGHlSFqE=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17 h1:Mqr/V5gvrhA2gvgnF42Zh5iMiQNcOYthFYwCyrnuWlc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17/go.mod h1:aLJpZlCmjE+V+KtN1q1uyZkfnUWpQGpbsn89XPKyzfU=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.17 h1:Roo69qTpfu8OlJ2Tb7pAYVuF0CpuUMB0IYWwYP/4DZM=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.17/go.mod h1:NcWPxQzGM1USQggaTVwz6VpqMZPX1CvDJLDh6jnOCa4=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 h1:KypMCbLPPHEmf9DgMGw51jMj77VfGPAN2Kv4cfhlfgI=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4/go.mod h1:Vz1JQXliGcQktFTN/LN6uGppAIRoLBR2bMvIMP0gOjc=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.19 h1:FLMkfEiRjhgeDTCjjLoc3URo/TBkgeQbocA78lfkzSI=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.19/go.mod h1:Vx+GucNSsdhaxs3aZIKfSUjKVGsxN25nX2SRcdhuw08=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19 h1:rfprUlsdzgl7ZL2KlXiUAoJnI/VxfHCvDFr2QDFj6u4=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19/go.mod h1:SCWkEdRq8/7EK60NcvvQ6NXKuTcchAD4ROAsC37VEZE=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.17 h1:u+EfGmksnJc/x5tq3A+OD7LrMbSSR/5TrKLvkdy/fhY=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.17/go.mod h1:VaMx6302JHax2vHJWgRo+5n9zvbacs3bLU/23DNQrTY=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.61.2 h1:Kp6PWAlXwP1UvIflkIP6MFZYBNDCa4mFCGtxrpICVOg=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.61.2/go.mod h1:5FmD/Dqq57gP+XwaUnd5WFPipAuzrf0HmupX27Gvjvc=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.22.7 h1:pIaGg+08llrP7Q5aiz9ICWbY8cqhTkyy+0SHvfzQpTc=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.22.7/go.mod h1:eEygMHnTKH/3kNp9Jr1n3PdejuSNcgwLe1dWgQtO0VQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.7 h1:/Cfdu0XV3mONYKaOt1Gr0k1KvQzkzPyiKUdlWJqy+J4=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.7/go.mod h1:bCbAxKDqNvkHxRaIMnyVPXPo+OaPRwvmgzMxbz1VKSA=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.30.7 h1:NKTa1eqZYw8tiHSRGpP0VtTdub/8KNk8sDkNPFaOKDE=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.30.7/go.mod h1:NXi1dIAGteSaRLqYgarlhP/Ij0cFT+qmCwiJqWh/U5o=
|
||||
github.com/aws/smithy-go v1.20.4 h1:2HK1zBdPgRbjFOHlfeQZfpC4r72MOb9bZkiFwggKO+4=
|
||||
github.com/aws/smithy-go v1.20.4/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
|
||||
github.com/blinkbean/dingtalk v1.1.3 h1:MbidFZYom7DTFHD/YIs+eaI7kRy52kmWE/sy0xjo6E4=
|
||||
github.com/blinkbean/dingtalk v1.1.3/go.mod h1:9BaLuGSBqY3vT5hstValh48DbsKO7vaHaJnG9pXwbto=
|
||||
github.com/cactus/go-statsd-client/statsd v0.0.0-20200423205355-cb0885a1018c/go.mod h1:l/bIBLeOl9eX+wxJAzxS4TveKRtAqlyDpHjhkfO0MEI=
|
||||
@@ -138,8 +138,8 @@ github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn
|
||||
github.com/clbanning/mxj/v2 v2.5.6 h1:Jm4VaCI/+Ug5Q57IzEoZbwx4iQFA6wkXv72juUSeK+g=
|
||||
github.com/clbanning/mxj/v2 v2.5.6/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/cloudflare-go v0.97.0 h1:feZRGiRF1EbljnNIYdt8014FnOLtC3CCvgkLXu915ks=
|
||||
github.com/cloudflare/cloudflare-go v0.97.0/go.mod h1:JXRwuTfHpe5xFg8xytc2w0XC6LcrFsBVMS4WlVaiGg8=
|
||||
github.com/cloudflare/cloudflare-go v0.104.0 h1:R/lB0dZupaZbOgibAH/BRrkFbZ6Acn/WsKg2iX2xXuY=
|
||||
github.com/cloudflare/cloudflare-go v0.104.0/go.mod h1:pfUQ4PIG4ISI0/Mmc21Bp86UnFU0ktmPf3iTgbSL+cM=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
@@ -147,8 +147,9 @@ github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI=
|
||||
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
github.com/dave/jennifer v1.6.1/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3RmGZc=
|
||||
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/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/domodwyer/mailyak/v3 v3.6.2 h1:x3tGMsyFhTCaxp6ycgR0FE/bu5QiNp+hetUuCOBXMn8=
|
||||
@@ -173,11 +174,11 @@ github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSe
|
||||
github.com/gammazero/toposort v0.1.1/go.mod h1:H2cozTnNpMw0hg2VHAYsAxmkHXBYroNangj2NTBQDvw=
|
||||
github.com/ganigeorgiev/fexpr v0.4.1 h1:hpUgbUEEWIZhSDBtf4M9aUNfQQ0BZkGRaMePy7Gcx5k=
|
||||
github.com/ganigeorgiev/fexpr v0.4.1/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO2WtJkF5drE=
|
||||
github.com/go-acme/lego/v4 v4.17.4 h1:h0nePd3ObP6o7kAkndtpTzCw8shOZuWckNYeUQwo36Q=
|
||||
github.com/go-acme/lego/v4 v4.17.4/go.mod h1:dU94SvPNqimEeb7EVilGGSnS0nU1O5Exir0pQ4QFL4U=
|
||||
github.com/go-acme/lego/v4 v4.19.2 h1:Y8hrmMvWETdqzzkRly7m98xtPJJivWFsgWi8fcvZo+Y=
|
||||
github.com/go-acme/lego/v4 v4.19.2/go.mod h1:wtDe3dDkmV4/oI2nydpNXSJpvV10J9RCyZ6MbYxNtlQ=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-jose/go-jose/v4 v4.0.2 h1:R3l3kkBds16bO7ZFAEEcofK0MkrAJt3jlJznWZG0nvk=
|
||||
github.com/go-jose/go-jose/v4 v4.0.2/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
|
||||
github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E=
|
||||
github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
@@ -214,15 +215,18 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
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.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
@@ -239,30 +243,26 @@ github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20240625030939-27f56978b8b0 h1:e+8XbKB6IMn8A4OAyZccO4pYfB3s7bt6azNIPE7AnPg=
|
||||
github.com/google/pprof v0.0.0-20240625030939-27f56978b8b0/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
|
||||
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/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM=
|
||||
github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA=
|
||||
github.com/google/uuid v1.1.2/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/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI=
|
||||
github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA=
|
||||
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/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA=
|
||||
github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s=
|
||||
github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
|
||||
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog=
|
||||
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.114 h1:X3E16S6AUZsQKhJIQ5kNnylnp0GtSy2YhIbxfvDavtU=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.114/go.mod h1:JWz2ujO9X3oU5wb6kXp+DpR2UuDj2SldDbX8T0FSuhI=
|
||||
github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
@@ -281,6 +281,7 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
|
||||
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
@@ -309,8 +310,8 @@ github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxU
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
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/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs=
|
||||
github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk=
|
||||
github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
|
||||
github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
@@ -318,6 +319,7 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
@@ -333,8 +335,9 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo=
|
||||
github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk=
|
||||
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/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pocketbase/dbx v1.10.1 h1:cw+vsyfCJD8YObOVeqb93YErnlxwYMkNZ4rwN0G0AaA=
|
||||
github.com/pocketbase/dbx v1.10.1/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWKhu2vhMs=
|
||||
github.com/pocketbase/pocketbase v0.22.18 h1:yVckUhi5GDORqCb0BbtlvRB1CVxHY9HO9btEaeZHVJU=
|
||||
@@ -377,19 +380,24 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
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/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
|
||||
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.898/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.992 h1:266lOve+E8vzhnrb/Mr05Ee+oxXD9C82JiusY/AZqXw=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1017 h1:OymmfmyFkvHirY3WHsoRT3cdTEsqygLbMn8jM41erK4=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1017/go.mod h1:gnLxGXlLmF+jDqWR1/RVoF/UUwxQxomQhkc0oN7KeuI=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.992/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.898 h1:LoYv5u+gUoFpU/AmIuTRG/2KiEkdm9gCC0dTvk8WITQ=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.898/go.mod h1:c1j6YQ+vCbeA8kJ59Im4UnMd1GxovlpPBDhGZoewfn8=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1002/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1017 h1:SXrldOXwgomYuATVAuz5ofpTjB+99qVELgdy5R5kMgI=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1017/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1002 h1:QwE0dRkAAbdf+eACnkNULgDn9ZKUJpPWRyXdqJolP5E=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1002/go.mod h1:WdC0FYbqYhJwQ3kbqri6hVP5HAEp+rzX9FToItTAzUg=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.992 h1:A6O89OlCJQUpNxGqC/E5By04UNKBryIt5olQIGOx8mg=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.992/go.mod h1:BcvC7ZPdSlhRggVq4J1ToJlgv8bmODIAuSo0naFZOLo=
|
||||
github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM=
|
||||
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
|
||||
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
||||
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
||||
github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o=
|
||||
github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
|
||||
github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg=
|
||||
@@ -398,21 +406,27 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
||||
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
|
||||
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.mongodb.org/mongo-driver v1.12.0 h1:aPx33jmn/rQuJXPQLZQ8NtfPQG8CaqgLThFtqRb0PiE=
|
||||
go.mongodb.org/mongo-driver v1.12.0/go.mod h1:AZkxhPnFJUoH7kZlFkVKucV20K387miPfm7oimrSmK0=
|
||||
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.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
|
||||
go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
|
||||
go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
|
||||
go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
|
||||
go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
|
||||
go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
|
||||
go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
|
||||
go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw=
|
||||
go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
|
||||
go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc=
|
||||
go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8=
|
||||
go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4=
|
||||
go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ=
|
||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
gocloud.dev v0.37.0 h1:XF1rN6R0qZI/9DYjN16Uy0durAmSlf58DHOcb28GPro=
|
||||
@@ -423,13 +437,17 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
||||
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
|
||||
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@@ -451,8 +469,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
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.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
|
||||
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
|
||||
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -462,8 +480,10 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
@@ -472,11 +492,12 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
|
||||
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
|
||||
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
|
||||
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
|
||||
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -497,6 +518,7 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@@ -508,8 +530,10 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
|
||||
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
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.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -518,24 +542,28 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||
golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
|
||||
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
|
||||
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
|
||||
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.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.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
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.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
||||
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
||||
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
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/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
|
||||
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@@ -549,8 +577,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
|
||||
golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
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.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
|
||||
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
|
||||
golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE=
|
||||
golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -561,27 +589,28 @@ gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJ
|
||||
gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
|
||||
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
|
||||
gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
|
||||
google.golang.org/api v0.189.0 h1:equMo30LypAkdkLMBqfeIqtyAnlyig1JSZArl4XPwdI=
|
||||
google.golang.org/api v0.189.0/go.mod h1:FLWGJKb0hb+pU2j+rJqwbnsF+ym+fQs73rbJ+KAUgy8=
|
||||
google.golang.org/api v0.197.0 h1:x6CwqQLsFiA5JKAiGyGBjc2bNtHtLddhJCE2IKuhhcQ=
|
||||
google.golang.org/api v0.197.0/go.mod h1:AuOuo20GoQ331nq7DquGHlU6d+2wN2fZ8O0ta60nRNw=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20240722135656-d784300faade h1:lKFsS7wpngDgSCeFn7MoLy+wBDQZ1UQIJD4UNM1Qvkg=
|
||||
google.golang.org/genproto v0.0.0-20240722135656-d784300faade/go.mod h1:FfBgJBJg9GcpPvKIuHSZ/aE1g2ecGL74upMzGZjiGEY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d h1:kHjw/5UfflP/L5EbledDrcG4C2597RtymmGRZvHiCuY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d/go.mod h1:mw8MG/Qz5wfgYr6VqVCiZcHe/GJEfI+oGGDCohaVgB0=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a h1:hqK4+jJZXCU4pW7jsAdGOVFIfLHQeV7LaizZKnZ84HI=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
|
||||
google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 h1:BulPr26Jqjnd4eYDVe+YvyR7Yc2vJGkO5/0UxD0/jZU=
|
||||
google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:hL97c3SYopEHblzpxRL4lSs523++l8DYxGM1FQiYmb4=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed h1:3RgNmBoI9MZhsj3QxC+AP/qQhNwpCLOvYDYYsFrhFt0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
|
||||
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
|
||||
google.golang.org/grpc v1.66.1 h1:hO5qAXR19+/Z44hmvIM4dQFMSYX9XcWsByfoxutBpAM=
|
||||
google.golang.org/grpc v1.66.1/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
|
||||
@@ -20,11 +20,12 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
configTypeTencent = "tencent"
|
||||
configTypeAliyun = "aliyun"
|
||||
configTypeCloudflare = "cloudflare"
|
||||
configTypeNamesilo = "namesilo"
|
||||
configTypeGodaddy = "godaddy"
|
||||
configTypeAliyun = "aliyun"
|
||||
configTypeTencent = "tencent"
|
||||
configTypeHuaweicloud = "huaweicloud"
|
||||
configTypeCloudflare = "cloudflare"
|
||||
configTypeNamesilo = "namesilo"
|
||||
configTypeGodaddy = "godaddy"
|
||||
)
|
||||
|
||||
const defaultSSLProvider = "letsencrypt"
|
||||
@@ -94,10 +95,12 @@ func Get(record *models.Record) (Applicant, error) {
|
||||
Nameservers: record.GetString("nameservers"),
|
||||
}
|
||||
switch access.GetString("configType") {
|
||||
case configTypeTencent:
|
||||
return NewTencent(option), nil
|
||||
case configTypeAliyun:
|
||||
return NewAliyun(option), nil
|
||||
case configTypeTencent:
|
||||
return NewTencent(option), nil
|
||||
case configTypeHuaweicloud:
|
||||
return NewHuaweiCloud(option), nil
|
||||
case configTypeCloudflare:
|
||||
return NewCloudflare(option), nil
|
||||
case configTypeNamesilo:
|
||||
@@ -172,13 +175,7 @@ func apply(option *ApplyOption, provider challenge.Provider) (*Certificate, erro
|
||||
}
|
||||
myUser.Registration = reg
|
||||
|
||||
domains := []string{option.Domain}
|
||||
|
||||
// 如果是通配置符域名,把根域名也加入
|
||||
if strings.HasPrefix(option.Domain, "*.") && len(strings.Split(option.Domain, ".")) == 3 {
|
||||
rootDomain := strings.TrimPrefix(option.Domain, "*.")
|
||||
domains = append(domains, rootDomain)
|
||||
}
|
||||
domains := strings.Split(option.Domain, ";")
|
||||
|
||||
request := certificate.ObtainRequest{
|
||||
Domains: domains,
|
||||
|
||||
35
internal/applicant/huaweicloud.go
Normal file
35
internal/applicant/huaweicloud.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package applicant
|
||||
|
||||
import (
|
||||
"certimate/internal/domain"
|
||||
"encoding/json"
|
||||
"os"
|
||||
|
||||
huaweicloudProvider "github.com/go-acme/lego/v4/providers/dns/huaweicloud"
|
||||
)
|
||||
|
||||
type huaweicloud struct {
|
||||
option *ApplyOption
|
||||
}
|
||||
|
||||
func NewHuaweiCloud(option *ApplyOption) Applicant {
|
||||
return &huaweicloud{
|
||||
option: option,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *huaweicloud) Apply() (*Certificate, error) {
|
||||
|
||||
access := &domain.HuaweiCloudAccess{}
|
||||
json.Unmarshal([]byte(t.option.Access), access)
|
||||
|
||||
os.Setenv("HUAWEICLOUD_REGION", access.Region) // 华为云的 SDK 要求必须传一个区域,实际上 DNS-01 流程里用不到,但不传会报错
|
||||
os.Setenv("HUAWEICLOUD_ACCESS_KEY_ID", access.AccessKeyId)
|
||||
os.Setenv("HUAWEICLOUD_SECRET_ACCESS_KEY", access.SecretAccessKey)
|
||||
dnsProvider, err := huaweicloudProvider.NewDNSProvider()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return apply(t.option, dnsProvider)
|
||||
}
|
||||
@@ -5,11 +5,14 @@ import (
|
||||
"certimate/internal/utils/rand"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
|
||||
ssl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205"
|
||||
cdn "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn/v20180606"
|
||||
)
|
||||
|
||||
type tencentCdn struct {
|
||||
@@ -89,14 +92,29 @@ func (t *tencentCdn) deploy(certId string) error {
|
||||
// 实例化要请求产品的client对象,clientProfile是可选的
|
||||
client, _ := ssl.NewClient(t.credential, "", cpf)
|
||||
|
||||
|
||||
|
||||
// 实例化一个请求对象,每个接口都会对应一个request对象
|
||||
request := ssl.NewDeployCertificateInstanceRequest()
|
||||
|
||||
request.CertificateId = common.StringPtr(certId)
|
||||
request.InstanceIdList = common.StringPtrs([]string{t.option.Domain})
|
||||
request.ResourceType = common.StringPtr("cdn")
|
||||
request.Status = common.Int64Ptr(1)
|
||||
|
||||
// 如果是泛域名就从cdn列表下获取SSL证书中的可用域名
|
||||
if(strings.Contains(t.option.Domain, "*")){
|
||||
list, errGetList := t.getDomainList()
|
||||
if errGetList != nil {
|
||||
return fmt.Errorf("failed to get certificate domain list: %w", errGetList)
|
||||
}
|
||||
if list == nil || len(list) == 0 {
|
||||
return fmt.Errorf("failed to get certificate domain list: empty list.")
|
||||
}
|
||||
request.InstanceIdList = common.StringPtrs(list)
|
||||
}else{ // 否则直接使用传入的域名
|
||||
request.InstanceIdList = common.StringPtrs([]string{t.option.Domain})
|
||||
}
|
||||
|
||||
// 返回的resp是一个DeployCertificateInstanceResponse的实例,与请求对象对应
|
||||
resp, err := client.DeployCertificateInstance(request)
|
||||
|
||||
@@ -106,3 +124,27 @@ func (t *tencentCdn) deploy(certId string) error {
|
||||
t.infos = append(t.infos, toStr("部署证书", resp.Response))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *tencentCdn) getDomainList() ([]string, error) {
|
||||
cpf := profile.NewClientProfile()
|
||||
cpf.HttpProfile.Endpoint = "cdn.tencentcloudapi.com"
|
||||
client, _ := cdn.NewClient(t.credential, "", cpf)
|
||||
|
||||
request := cdn.NewDescribeCertDomainsRequest()
|
||||
|
||||
cert := base64.StdEncoding.EncodeToString([]byte(t.option.Certificate.Certificate))
|
||||
request.Cert = &cert
|
||||
|
||||
|
||||
response, err := client.DescribeCertDomains(request)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get domain list: %w", err)
|
||||
}
|
||||
|
||||
domains := make([]string, 0)
|
||||
for _, domain := range response.Response.Domains {
|
||||
domains = append(domains, *domain)
|
||||
}
|
||||
|
||||
return domains, nil
|
||||
}
|
||||
|
||||
@@ -10,6 +10,12 @@ type TencentAccess struct {
|
||||
SecretKey string `json:"secretKey"`
|
||||
}
|
||||
|
||||
type HuaweiCloudAccess struct {
|
||||
Region string `json:"region"`
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
}
|
||||
|
||||
type CloudflareAccess struct {
|
||||
DnsApiToken string `json:"dnsApiToken"`
|
||||
}
|
||||
|
||||
@@ -31,11 +31,12 @@ func Send(title, content string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
n := notifyPackage.New()
|
||||
// 添加推送渠道
|
||||
notifyPackage.UseServices(notifiers...)
|
||||
n.UseServices(notifiers...)
|
||||
|
||||
// 发送消息
|
||||
return notifyPackage.Send(context.Background(), title, content)
|
||||
return n.Send(context.Background(), title, content)
|
||||
}
|
||||
|
||||
func getNotifiers() ([]notifyPackage.Notifier, error) {
|
||||
|
||||
92
migrations/1728610007_updated_access.go
Normal file
92
migrations/1728610007_updated_access.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/pocketbase/dbx"
|
||||
"github.com/pocketbase/pocketbase/daos"
|
||||
m "github.com/pocketbase/pocketbase/migrations"
|
||||
"github.com/pocketbase/pocketbase/models/schema"
|
||||
)
|
||||
|
||||
func init() {
|
||||
m.Register(func(db dbx.Builder) error {
|
||||
dao := daos.New(db);
|
||||
|
||||
collection, err := dao.FindCollectionByNameOrId("4yzbv8urny5ja1e")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// update
|
||||
edit_configType := &schema.SchemaField{}
|
||||
if err := json.Unmarshal([]byte(`{
|
||||
"system": false,
|
||||
"id": "hwy7m03o",
|
||||
"name": "configType",
|
||||
"type": "select",
|
||||
"required": false,
|
||||
"presentable": false,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"maxSelect": 1,
|
||||
"values": [
|
||||
"aliyun",
|
||||
"tencent",
|
||||
"huaweicloud",
|
||||
"qiniu",
|
||||
"cloudflare",
|
||||
"namesilo",
|
||||
"godaddy",
|
||||
"local",
|
||||
"ssh",
|
||||
"webhook"
|
||||
]
|
||||
}
|
||||
}`), edit_configType); err != nil {
|
||||
return err
|
||||
}
|
||||
collection.Schema.AddField(edit_configType)
|
||||
|
||||
return dao.SaveCollection(collection)
|
||||
}, func(db dbx.Builder) error {
|
||||
dao := daos.New(db);
|
||||
|
||||
collection, err := dao.FindCollectionByNameOrId("4yzbv8urny5ja1e")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// update
|
||||
edit_configType := &schema.SchemaField{}
|
||||
if err := json.Unmarshal([]byte(`{
|
||||
"system": false,
|
||||
"id": "hwy7m03o",
|
||||
"name": "configType",
|
||||
"type": "select",
|
||||
"required": false,
|
||||
"presentable": false,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"maxSelect": 1,
|
||||
"values": [
|
||||
"aliyun",
|
||||
"tencent",
|
||||
"huaweicloud",
|
||||
"ssh",
|
||||
"webhook",
|
||||
"cloudflare",
|
||||
"qiniu",
|
||||
"namesilo",
|
||||
"godaddy",
|
||||
"local"
|
||||
]
|
||||
}
|
||||
}`), edit_configType); err != nil {
|
||||
return err
|
||||
}
|
||||
collection.Schema.AddField(edit_configType)
|
||||
|
||||
return dao.SaveCollection(collection)
|
||||
})
|
||||
}
|
||||
322
ui/dist/assets/index--un-5Tw_.js
vendored
322
ui/dist/assets/index--un-5Tw_.js
vendored
File diff suppressed because one or more lines are too long
1
ui/dist/assets/index-DOft-CKV.css
vendored
Normal file
1
ui/dist/assets/index-DOft-CKV.css
vendored
Normal file
File diff suppressed because one or more lines are too long
332
ui/dist/assets/index-DpHAV802.js
vendored
Normal file
332
ui/dist/assets/index-DpHAV802.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
ui/dist/assets/index-I--T0qY3.css
vendored
1
ui/dist/assets/index-I--T0qY3.css
vendored
File diff suppressed because one or more lines are too long
1
ui/dist/imgs/providers/huaweicloud.svg
vendored
Normal file
1
ui/dist/imgs/providers/huaweicloud.svg
vendored
Normal file
@@ -0,0 +1 @@
|
||||
<svg t="1728551595312" class="icon" viewBox="0 0 1027 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4252" width="200" height="200"><path d="M378.88 143.36c20.48-6.826667 40.96-10.24 61.44-13.653333 23.893333 30.72 30.72 71.68 40.96 109.226666 6.826667 40.96 13.653333 81.92 13.653333 122.88 6.826667 27.306667 3.413333 58.026667 3.413334 85.333334s-3.413333 51.2 0 78.506666c0 37.546667-3.413333 71.68-3.413334 109.226667-6.826667 23.893333 0 47.786667-6.826666 71.68-10.24-3.413333-13.653333-13.653333-17.066667-20.48-40.96-61.44-78.506667-122.88-112.64-187.733333-34.133333-68.266667-68.266667-136.533333-71.68-215.04-6.826667-61.44 34.133333-119.466667 92.16-139.946667z m211.626667-10.24c6.826667-3.413333 10.24 0 17.066666 0 27.306667 6.826667 58.026667 10.24 81.92 27.306667s44.373333 40.96 51.2 68.266666c10.24 34.133333 6.826667 71.68 0 105.813334-10.24 44.373333-30.72 85.333333-51.2 126.293333-6.826667 13.653333-13.653333 23.893333-20.48 37.546667-10.24 23.893333-27.306667 47.786667-40.96 71.68-23.893333 40.96-47.786667 75.093333-71.68 116.053333-3.413333 3.413333-6.826667 13.653333-13.653333 6.826667-3.413333-40.96-6.826667-81.92-10.24-126.293334-6.826667-54.613333-3.413333-105.813333-3.413333-160.426666 3.413333-34.133333 3.413333-71.68 6.826666-105.813334 6.826667-40.96 13.653333-85.333333 27.306667-126.293333 13.653333-10.24 13.653333-30.72 27.306667-40.96zM160.426667 266.24c3.413333 0 6.826667 6.826667 10.24 10.24 98.986667 129.706667 187.733333 266.24 259.413333 413.013333 6.826667 10.24 13.653333 23.893333 13.653333 37.546667-13.653333-3.413333-23.893333-10.24-34.133333-17.066667-64.853333-34.133333-129.706667-71.68-194.56-109.226666-23.893333-17.066667-47.786667-34.133333-68.266667-51.2-40.96-27.306667-68.266667-78.506667-64.853333-129.706667 3.413333-61.44 37.546667-112.64 78.506667-153.6z m706.56 0h6.826666c17.066667 23.893333 40.96 47.786667 54.613334 75.093333 13.653333 23.893333 20.48 54.613333 23.893333 81.92 0 30.72-10.24 64.853333-34.133333 88.746667-13.653333 13.653333-23.893333 27.306667-40.96 37.546667-78.506667 61.44-163.84 109.226667-252.586667 153.6-13.653333 6.826667-23.893333 17.066667-40.96 17.066666 3.413333-17.066667 13.653333-34.133333 20.48-47.786666 58.026667-119.466667 129.706667-232.106667 208.213333-341.333334 17.066667-17.066667 37.546667-40.96 54.613334-64.853333z m-856.746667 273.066667c3.413333-3.413333 0-10.24 6.826667-13.653334 10.24 3.413333 20.48 10.24 27.306666 13.653334 122.88 68.266667 245.76 136.533333 365.226667 211.626666 3.413333 3.413333 6.826667 6.826667 6.826667 10.24H180.906667c-47.786667 0-92.16-20.48-126.293334-54.613333-27.306667-30.72-51.2-71.68-54.613333-112.64 6.826667-17.066667 3.413333-34.133333 10.24-54.613333z m983.04-3.413334c6.826667-3.413333 17.066667-10.24 23.893333-6.826666 0 17.066667 6.826667 37.546667 6.826667 54.613333-3.413333 23.893333-3.413333 44.373333-13.653333 64.853333-6.826667 17.066667-17.066667 37.546667-30.72 51.2-17.066667 13.653333-27.306667 30.72-47.786667 40.96-20.48 17.066667-51.2 20.48-75.093333 23.893334h-245.76c3.413333-3.413333 3.413333-6.826667 6.826666-10.24 122.88-78.506667 249.173333-150.186667 375.466667-218.453334zM184.32 798.72c44.373333-3.413333 88.746667 0 133.12-6.826667 30.72 0 64.853333-3.413333 95.573333 0-6.826667 13.653333-23.893333 20.48-34.133333 27.306667-34.133333 23.893333-68.266667 44.373333-105.813333 61.44s-81.92 10.24-112.64-13.653333c-23.893333-17.066667-44.373333-44.373333-58.026667-68.266667h81.92z m433.493333-6.826667c30.72-3.413333 61.44 0 95.573334 0 40.96 3.413333 85.333333 0 129.706666 6.826667 30.72 3.413333 61.44 0 88.746667 3.413333-10.24 20.48-27.306667 40.96-44.373333 58.026667-27.306667 27.306667-68.266667 40.96-105.813334 34.133333-34.133333-10.24-61.44-30.72-92.16-47.786666-17.066667-10.24-30.72-20.48-47.786666-30.72-10.24-10.24-17.066667-13.653333-23.893334-23.893334z" fill="#C71F1E" p-id="4253"></path></svg>
|
||||
4
ui/dist/index.html
vendored
4
ui/dist/index.html
vendored
@@ -5,8 +5,8 @@
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Certimate - Your Trusted SSL Automation Partner</title>
|
||||
<script type="module" crossorigin src="/assets/index--un-5Tw_.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-I--T0qY3.css">
|
||||
<script type="module" crossorigin src="/assets/index-DpHAV802.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-DOft-CKV.css">
|
||||
</head>
|
||||
<body class="bg-background">
|
||||
<div id="root"></div>
|
||||
|
||||
1
ui/public/imgs/providers/huaweicloud.svg
Normal file
1
ui/public/imgs/providers/huaweicloud.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg t="1728551595312" class="icon" viewBox="0 0 1027 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4252" width="200" height="200"><path d="M378.88 143.36c20.48-6.826667 40.96-10.24 61.44-13.653333 23.893333 30.72 30.72 71.68 40.96 109.226666 6.826667 40.96 13.653333 81.92 13.653333 122.88 6.826667 27.306667 3.413333 58.026667 3.413334 85.333334s-3.413333 51.2 0 78.506666c0 37.546667-3.413333 71.68-3.413334 109.226667-6.826667 23.893333 0 47.786667-6.826666 71.68-10.24-3.413333-13.653333-13.653333-17.066667-20.48-40.96-61.44-78.506667-122.88-112.64-187.733333-34.133333-68.266667-68.266667-136.533333-71.68-215.04-6.826667-61.44 34.133333-119.466667 92.16-139.946667z m211.626667-10.24c6.826667-3.413333 10.24 0 17.066666 0 27.306667 6.826667 58.026667 10.24 81.92 27.306667s44.373333 40.96 51.2 68.266666c10.24 34.133333 6.826667 71.68 0 105.813334-10.24 44.373333-30.72 85.333333-51.2 126.293333-6.826667 13.653333-13.653333 23.893333-20.48 37.546667-10.24 23.893333-27.306667 47.786667-40.96 71.68-23.893333 40.96-47.786667 75.093333-71.68 116.053333-3.413333 3.413333-6.826667 13.653333-13.653333 6.826667-3.413333-40.96-6.826667-81.92-10.24-126.293334-6.826667-54.613333-3.413333-105.813333-3.413333-160.426666 3.413333-34.133333 3.413333-71.68 6.826666-105.813334 6.826667-40.96 13.653333-85.333333 27.306667-126.293333 13.653333-10.24 13.653333-30.72 27.306667-40.96zM160.426667 266.24c3.413333 0 6.826667 6.826667 10.24 10.24 98.986667 129.706667 187.733333 266.24 259.413333 413.013333 6.826667 10.24 13.653333 23.893333 13.653333 37.546667-13.653333-3.413333-23.893333-10.24-34.133333-17.066667-64.853333-34.133333-129.706667-71.68-194.56-109.226666-23.893333-17.066667-47.786667-34.133333-68.266667-51.2-40.96-27.306667-68.266667-78.506667-64.853333-129.706667 3.413333-61.44 37.546667-112.64 78.506667-153.6z m706.56 0h6.826666c17.066667 23.893333 40.96 47.786667 54.613334 75.093333 13.653333 23.893333 20.48 54.613333 23.893333 81.92 0 30.72-10.24 64.853333-34.133333 88.746667-13.653333 13.653333-23.893333 27.306667-40.96 37.546667-78.506667 61.44-163.84 109.226667-252.586667 153.6-13.653333 6.826667-23.893333 17.066667-40.96 17.066666 3.413333-17.066667 13.653333-34.133333 20.48-47.786666 58.026667-119.466667 129.706667-232.106667 208.213333-341.333334 17.066667-17.066667 37.546667-40.96 54.613334-64.853333z m-856.746667 273.066667c3.413333-3.413333 0-10.24 6.826667-13.653334 10.24 3.413333 20.48 10.24 27.306666 13.653334 122.88 68.266667 245.76 136.533333 365.226667 211.626666 3.413333 3.413333 6.826667 6.826667 6.826667 10.24H180.906667c-47.786667 0-92.16-20.48-126.293334-54.613333-27.306667-30.72-51.2-71.68-54.613333-112.64 6.826667-17.066667 3.413333-34.133333 10.24-54.613333z m983.04-3.413334c6.826667-3.413333 17.066667-10.24 23.893333-6.826666 0 17.066667 6.826667 37.546667 6.826667 54.613333-3.413333 23.893333-3.413333 44.373333-13.653333 64.853333-6.826667 17.066667-17.066667 37.546667-30.72 51.2-17.066667 13.653333-27.306667 30.72-47.786667 40.96-20.48 17.066667-51.2 20.48-75.093333 23.893334h-245.76c3.413333-3.413333 3.413333-6.826667 6.826666-10.24 122.88-78.506667 249.173333-150.186667 375.466667-218.453334zM184.32 798.72c44.373333-3.413333 88.746667 0 133.12-6.826667 30.72 0 64.853333-3.413333 95.573333 0-6.826667 13.653333-23.893333 20.48-34.133333 27.306667-34.133333 23.893333-68.266667 44.373333-105.813333 61.44s-81.92 10.24-112.64-13.653333c-23.893333-17.066667-44.373333-44.373333-58.026667-68.266667h81.92z m433.493333-6.826667c30.72-3.413333 61.44 0 95.573334 0 40.96 3.413333 85.333333 0 129.706666 6.826667 30.72 3.413333 61.44 0 88.746667 3.413333-10.24 20.48-27.306667 40.96-44.373333 58.026667-27.306667 27.306667-68.266667 40.96-105.813334 34.133333-34.133333-10.24-61.44-30.72-92.16-47.786666-17.066667-10.24-30.72-20.48-47.786666-30.72-10.24-10.24-17.066667-13.653333-23.893334-23.893334z" fill="#C71F1E" p-id="4253"></path></svg>
|
||||
@@ -24,9 +24,11 @@ import { PbErrorData } from "@/domain/base";
|
||||
|
||||
const AccessAliyunForm = ({
|
||||
data,
|
||||
op,
|
||||
onAfterReq,
|
||||
}: {
|
||||
data?: Access;
|
||||
op: "add" | "edit" | "copy";
|
||||
onAfterReq: () => void;
|
||||
}) => {
|
||||
const { addAccess, updateAccess } = useConfig();
|
||||
@@ -69,6 +71,7 @@ const AccessAliyunForm = ({
|
||||
};
|
||||
|
||||
try {
|
||||
req.id = op == "copy" ? "" : req.id;
|
||||
const rs = await save(req);
|
||||
|
||||
onAfterReq();
|
||||
@@ -76,10 +79,11 @@ const AccessAliyunForm = ({
|
||||
req.id = rs.id;
|
||||
req.created = rs.created;
|
||||
req.updated = rs.updated;
|
||||
if (data.id) {
|
||||
if (data.id && op == "edit") {
|
||||
updateAccess(req);
|
||||
return;
|
||||
}
|
||||
console.log(req);
|
||||
addAccess(req);
|
||||
} catch (e) {
|
||||
const err = e as ClientResponseError;
|
||||
|
||||
@@ -23,9 +23,11 @@ import { PbErrorData } from "@/domain/base";
|
||||
|
||||
const AccessCloudflareForm = ({
|
||||
data,
|
||||
op,
|
||||
onAfterReq,
|
||||
}: {
|
||||
data?: Access;
|
||||
op: "add" | "edit" | "copy";
|
||||
onAfterReq: () => void;
|
||||
}) => {
|
||||
const { addAccess, updateAccess } = useConfig();
|
||||
@@ -65,6 +67,7 @@ const AccessCloudflareForm = ({
|
||||
};
|
||||
|
||||
try {
|
||||
req.id = op == "copy" ? "" : req.id;
|
||||
const rs = await save(req);
|
||||
|
||||
onAfterReq();
|
||||
@@ -72,7 +75,7 @@ const AccessCloudflareForm = ({
|
||||
req.id = rs.id;
|
||||
req.created = rs.created;
|
||||
req.updated = rs.updated;
|
||||
if (data.id) {
|
||||
if (data.id && op == "edit") {
|
||||
updateAccess(req);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -10,16 +10,10 @@ import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import AccessTencentForm from "./AccessTencentForm";
|
||||
|
||||
import { Label } from "../ui/label";
|
||||
|
||||
import { Access, accessTypeMap } from "@/domain/access";
|
||||
import AccessAliyunForm from "./AccessAliyunForm";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
import AccessSSHForm from "./AccessSSHForm";
|
||||
import WebhookForm from "./AccessWebhookFrom";
|
||||
import { Label } from "../ui/label";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
@@ -29,14 +23,19 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "../ui/select";
|
||||
import AccessCloudflareForm from "./AccessCloudflareForm";
|
||||
import AccessAliyunForm from "./AccessAliyunForm";
|
||||
import AccessTencentForm from "./AccessTencentForm";
|
||||
import AccessHuaweicloudForm from "./AccessHuaweicloudForm";
|
||||
import AccessQiniuForm from "./AccessQiniuForm";
|
||||
import AccessCloudflareForm from "./AccessCloudflareForm";
|
||||
import AccessNamesiloForm from "./AccessNamesiloForm";
|
||||
import AccessGodaddyFrom from "./AccessGodaddyForm";
|
||||
import AccessLocalForm from "./AccessLocalForm";
|
||||
import AccessSSHForm from "./AccessSSHForm";
|
||||
import AccessWebhookForm from "./AccessWebhookFrom";
|
||||
|
||||
type TargetConfigEditProps = {
|
||||
op: "add" | "edit";
|
||||
op: "add" | "edit" | "copy";
|
||||
className?: string;
|
||||
trigger: React.ReactNode;
|
||||
data?: Access;
|
||||
@@ -56,50 +55,33 @@ export function AccessEdit({
|
||||
|
||||
let form = <> </>;
|
||||
switch (configType) {
|
||||
case "tencent":
|
||||
form = (
|
||||
<AccessTencentForm
|
||||
data={data}
|
||||
onAfterReq={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case "aliyun":
|
||||
form = (
|
||||
<AccessAliyunForm
|
||||
data={data}
|
||||
op={op}
|
||||
onAfterReq={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case "ssh":
|
||||
case "tencent":
|
||||
form = (
|
||||
<AccessSSHForm
|
||||
<AccessTencentForm
|
||||
data={data}
|
||||
op={op}
|
||||
onAfterReq={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case "webhook":
|
||||
case "huaweicloud":
|
||||
form = (
|
||||
<WebhookForm
|
||||
data={data}
|
||||
onAfterReq={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case "cloudflare":
|
||||
form = (
|
||||
<AccessCloudflareForm
|
||||
<AccessHuaweicloudForm
|
||||
data={data}
|
||||
op={op}
|
||||
onAfterReq={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
@@ -110,6 +92,18 @@ export function AccessEdit({
|
||||
form = (
|
||||
<AccessQiniuForm
|
||||
data={data}
|
||||
op={op}
|
||||
onAfterReq={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case "cloudflare":
|
||||
form = (
|
||||
<AccessCloudflareForm
|
||||
data={data}
|
||||
op={op}
|
||||
onAfterReq={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
@@ -120,6 +114,7 @@ export function AccessEdit({
|
||||
form = (
|
||||
<AccessNamesiloForm
|
||||
data={data}
|
||||
op={op}
|
||||
onAfterReq={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
@@ -130,6 +125,7 @@ export function AccessEdit({
|
||||
form = (
|
||||
<AccessGodaddyFrom
|
||||
data={data}
|
||||
op={op}
|
||||
onAfterReq={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
@@ -140,6 +136,29 @@ export function AccessEdit({
|
||||
form = (
|
||||
<AccessLocalForm
|
||||
data={data}
|
||||
op={op}
|
||||
onAfterReq={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case "ssh":
|
||||
form = (
|
||||
<AccessSSHForm
|
||||
data={data}
|
||||
op={op}
|
||||
onAfterReq={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case "webhook":
|
||||
form = (
|
||||
<AccessWebhookForm
|
||||
data={data}
|
||||
op={op}
|
||||
onAfterReq={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
@@ -159,11 +178,17 @@ export function AccessEdit({
|
||||
</DialogTrigger>
|
||||
<DialogContent className="sm:max-w-[600px] w-full dark:text-stone-200">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{op == "add" ? t('access.add') : t('access.edit')}</DialogTitle>
|
||||
<DialogTitle>
|
||||
{op == "add"
|
||||
? t("access.add")
|
||||
: op == "edit"
|
||||
? t("access.edit")
|
||||
: t("access.copy")}
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<ScrollArea className="max-h-[80vh]">
|
||||
<div className="container py-3">
|
||||
<Label>{t('access.type')}</Label>
|
||||
<Label>{t("access.type")}</Label>
|
||||
|
||||
<Select
|
||||
onValueChange={(val) => {
|
||||
@@ -172,11 +197,11 @@ export function AccessEdit({
|
||||
defaultValue={configType}
|
||||
>
|
||||
<SelectTrigger className="mt-3">
|
||||
<SelectValue placeholder={t('access.type.not.empty')} />
|
||||
<SelectValue placeholder={t("access.type.not.empty")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectLabel>{t('access.type')}</SelectLabel>
|
||||
<SelectLabel>{t("access.type")}</SelectLabel>
|
||||
{typeKeys.map((key) => (
|
||||
<SelectItem value={key} key={key}>
|
||||
<div
|
||||
@@ -189,7 +214,7 @@ export function AccessEdit({
|
||||
src={accessTypeMap.get(key)?.[1]}
|
||||
className="h-6 w-6"
|
||||
/>
|
||||
<div>{t(accessTypeMap.get(key)?.[0] || '')}</div>
|
||||
<div>{t(accessTypeMap.get(key)?.[0] || "")}</div>
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
|
||||
@@ -28,9 +28,11 @@ import { PbErrorData } from "@/domain/base";
|
||||
|
||||
const AccessGodaddyFrom = ({
|
||||
data,
|
||||
op,
|
||||
onAfterReq,
|
||||
}: {
|
||||
data?: Access;
|
||||
op: "add" | "edit" | "copy";
|
||||
onAfterReq: () => void;
|
||||
}) => {
|
||||
const { addAccess, updateAccess } = useConfig();
|
||||
@@ -74,6 +76,7 @@ const AccessGodaddyFrom = ({
|
||||
};
|
||||
|
||||
try {
|
||||
req.id = op == "copy" ? "" : req.id;
|
||||
const rs = await save(req);
|
||||
|
||||
onAfterReq();
|
||||
@@ -81,7 +84,7 @@ const AccessGodaddyFrom = ({
|
||||
req.id = rs.id;
|
||||
req.created = rs.created;
|
||||
req.updated = rs.updated;
|
||||
if (data.id) {
|
||||
if (data.id && op == "edit") {
|
||||
updateAccess(req);
|
||||
return;
|
||||
}
|
||||
|
||||
221
ui/src/components/certimate/AccessHuaweicloudForm.tsx
Normal file
221
ui/src/components/certimate/AccessHuaweicloudForm.tsx
Normal file
@@ -0,0 +1,221 @@
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
|
||||
import z from "zod";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
import { Access, accessFormType, HuaweicloudConfig, getUsageByConfigType } from "@/domain/access";
|
||||
import { save } from "@/repository/access";
|
||||
import { useConfig } from "@/providers/config";
|
||||
|
||||
import { ClientResponseError } from "pocketbase";
|
||||
import { PbErrorData } from "@/domain/base";
|
||||
|
||||
const AccessHuaweicloudForm = ({
|
||||
data,
|
||||
op,
|
||||
onAfterReq,
|
||||
}: {
|
||||
data?: Access;
|
||||
op: "add" | "edit" | "copy";
|
||||
onAfterReq: () => void;
|
||||
}) => {
|
||||
const { addAccess, updateAccess } = useConfig();
|
||||
const { t } = useTranslation();
|
||||
const formSchema = z.object({
|
||||
id: z.string().optional(),
|
||||
name: z.string().min(1, 'access.form.name.not.empty').max(64, t('zod.rule.string.max', { max: 64 })),
|
||||
configType: accessFormType,
|
||||
region: z.string().min(1, 'access.form.region.not.empty').max(64, t('zod.rule.string.max', { max: 64 })),
|
||||
accessKeyId: z.string().min(1, 'access.form.access.key.id.not.empty').max(64, t('zod.rule.string.max', { max: 64 })),
|
||||
secretAccessKey: z.string().min(1, 'access.form.access.key.secret.not.empty').max(64, t('zod.rule.string.max', { max: 64 })),
|
||||
});
|
||||
|
||||
let config: HuaweicloudConfig = {
|
||||
region: "cn-north-1",
|
||||
accessKeyId: "",
|
||||
secretAccessKey: "",
|
||||
};
|
||||
if (data) config = data.config as HuaweicloudConfig;
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
id: data?.id,
|
||||
name: data?.name || '',
|
||||
configType: "huaweicloud",
|
||||
region: config.region,
|
||||
accessKeyId: config.accessKeyId,
|
||||
secretAccessKey: config.secretAccessKey,
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = async (data: z.infer<typeof formSchema>) => {
|
||||
const req: Access = {
|
||||
id: data.id as string,
|
||||
name: data.name,
|
||||
configType: data.configType,
|
||||
usage: getUsageByConfigType(data.configType),
|
||||
config: {
|
||||
region: data.region,
|
||||
accessKeyId: data.accessKeyId,
|
||||
secretAccessKey: data.secretAccessKey,
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
req.id = op == "copy" ? "" : req.id;
|
||||
const rs = await save(req);
|
||||
|
||||
onAfterReq();
|
||||
|
||||
req.id = rs.id;
|
||||
req.created = rs.created;
|
||||
req.updated = rs.updated;
|
||||
if (data.id && op == "edit") {
|
||||
updateAccess(req);
|
||||
return;
|
||||
}
|
||||
console.log(req);
|
||||
addAccess(req);
|
||||
} catch (e) {
|
||||
const err = e as ClientResponseError;
|
||||
|
||||
Object.entries(err.response.data as PbErrorData).forEach(
|
||||
([key, value]) => {
|
||||
form.setError(key as keyof z.infer<typeof formSchema>, {
|
||||
type: "manual",
|
||||
message: value.message,
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="max-w-[35em] mx-auto mt-10">
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.stopPropagation();
|
||||
form.handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
className="space-y-8"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('name')}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t('access.form.name.not.empty')} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="id"
|
||||
render={({ field }) => (
|
||||
<FormItem className="hidden">
|
||||
<FormLabel>{t('access.form.config.field')}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="configType"
|
||||
render={({ field }) => (
|
||||
<FormItem className="hidden">
|
||||
<FormLabel>{t('access.form.config.field')}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="region"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('access.form.region')}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t('access.form.region.not.empty')} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="accessKeyId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('access.form.access.key.id')}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t('access.form.access.key.id.not.empty')} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="secretAccessKey"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('access.form.access.key.secret')}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t('access.form.access.key.secret.not.empty')} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t('save')}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccessHuaweicloudForm;
|
||||
@@ -27,9 +27,11 @@ import { PbErrorData } from "@/domain/base";
|
||||
|
||||
const AccessLocalForm = ({
|
||||
data,
|
||||
op,
|
||||
onAfterReq,
|
||||
}: {
|
||||
data?: Access;
|
||||
op: "add" | "edit" | "copy";
|
||||
onAfterReq: () => void;
|
||||
}) => {
|
||||
const { addAccess, updateAccess, reloadAccessGroups } = useConfig();
|
||||
@@ -79,6 +81,7 @@ const AccessLocalForm = ({
|
||||
};
|
||||
|
||||
try {
|
||||
req.id = op == "copy" ? "" : req.id;
|
||||
const rs = await save(req);
|
||||
|
||||
onAfterReq();
|
||||
@@ -86,7 +89,7 @@ const AccessLocalForm = ({
|
||||
req.id = rs.id;
|
||||
req.created = rs.created;
|
||||
req.updated = rs.updated;
|
||||
if (data.id) {
|
||||
if (data.id && op == "edit") {
|
||||
updateAccess(req);
|
||||
} else {
|
||||
addAccess(req);
|
||||
|
||||
@@ -23,9 +23,11 @@ import { PbErrorData } from "@/domain/base";
|
||||
|
||||
const AccessNamesiloForm = ({
|
||||
data,
|
||||
op,
|
||||
onAfterReq,
|
||||
}: {
|
||||
data?: Access;
|
||||
op: "add" | "edit" | "copy";
|
||||
onAfterReq: () => void;
|
||||
}) => {
|
||||
const { addAccess, updateAccess } = useConfig();
|
||||
@@ -64,6 +66,7 @@ const AccessNamesiloForm = ({
|
||||
};
|
||||
|
||||
try {
|
||||
req.id = op == "copy" ? "" : req.id;
|
||||
const rs = await save(req);
|
||||
|
||||
onAfterReq();
|
||||
@@ -71,7 +74,7 @@ const AccessNamesiloForm = ({
|
||||
req.id = rs.id;
|
||||
req.created = rs.created;
|
||||
req.updated = rs.updated;
|
||||
if (data.id) {
|
||||
if (data.id && op == "edit") {
|
||||
updateAccess(req);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -24,9 +24,11 @@ import { PbErrorData } from "@/domain/base";
|
||||
|
||||
const AccessQiniuForm = ({
|
||||
data,
|
||||
op,
|
||||
onAfterReq,
|
||||
}: {
|
||||
data?: Access;
|
||||
op: "add" | "edit" | "copy";
|
||||
onAfterReq: () => void;
|
||||
}) => {
|
||||
const { addAccess, updateAccess } = useConfig();
|
||||
@@ -69,6 +71,7 @@ const AccessQiniuForm = ({
|
||||
};
|
||||
|
||||
try {
|
||||
req.id = op == "copy" ? "" : req.id;
|
||||
const rs = await save(req);
|
||||
|
||||
onAfterReq();
|
||||
@@ -76,7 +79,7 @@ const AccessQiniuForm = ({
|
||||
req.id = rs.id;
|
||||
req.created = rs.created;
|
||||
req.updated = rs.updated;
|
||||
if (data.id) {
|
||||
if (data.id && op == "edit") {
|
||||
updateAccess(req);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -39,9 +39,11 @@ import { updateById } from "@/repository/access_group";
|
||||
|
||||
const AccessSSHForm = ({
|
||||
data,
|
||||
op,
|
||||
onAfterReq,
|
||||
}: {
|
||||
data?: Access;
|
||||
op: "add" | "edit" | "copy";
|
||||
onAfterReq: () => void;
|
||||
}) => {
|
||||
const {
|
||||
@@ -145,6 +147,7 @@ const AccessSSHForm = ({
|
||||
};
|
||||
|
||||
try {
|
||||
req.id = op == "copy" ? "" : req.id;
|
||||
const rs = await save(req);
|
||||
|
||||
onAfterReq();
|
||||
@@ -152,7 +155,7 @@ const AccessSSHForm = ({
|
||||
req.id = rs.id;
|
||||
req.created = rs.created;
|
||||
req.updated = rs.updated;
|
||||
if (data.id) {
|
||||
if (data.id && op == "edit") {
|
||||
updateAccess(req);
|
||||
} else {
|
||||
addAccess(req);
|
||||
|
||||
@@ -23,9 +23,11 @@ import { PbErrorData } from "@/domain/base";
|
||||
|
||||
const AccessTencentForm = ({
|
||||
data,
|
||||
op,
|
||||
onAfterReq,
|
||||
}: {
|
||||
data?: Access;
|
||||
op: "add" | "edit" | "copy";
|
||||
onAfterReq: () => void;
|
||||
}) => {
|
||||
const { addAccess, updateAccess } = useConfig();
|
||||
@@ -68,6 +70,7 @@ const AccessTencentForm = ({
|
||||
};
|
||||
|
||||
try {
|
||||
req.id = op == "copy" ? "" : req.id;
|
||||
const rs = await save(req);
|
||||
|
||||
onAfterReq();
|
||||
@@ -75,7 +78,7 @@ const AccessTencentForm = ({
|
||||
req.id = rs.id;
|
||||
req.created = rs.created;
|
||||
req.updated = rs.updated;
|
||||
if (data.id) {
|
||||
if (data.id && op == "edit") {
|
||||
updateAccess(req);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -23,9 +23,11 @@ import { PbErrorData } from "@/domain/base";
|
||||
|
||||
const WebhookForm = ({
|
||||
data,
|
||||
op,
|
||||
onAfterReq,
|
||||
}: {
|
||||
data?: Access;
|
||||
op: "add" | "edit" | "copy";
|
||||
onAfterReq: () => void;
|
||||
}) => {
|
||||
const { addAccess, updateAccess } = useConfig();
|
||||
@@ -64,6 +66,7 @@ const WebhookForm = ({
|
||||
};
|
||||
|
||||
try {
|
||||
req.id = op == "copy" ? "" : req.id;
|
||||
const rs = await save(req);
|
||||
|
||||
onAfterReq();
|
||||
@@ -71,7 +74,7 @@ const WebhookForm = ({
|
||||
req.id = rs.id;
|
||||
req.created = rs.created;
|
||||
req.updated = rs.updated;
|
||||
if (data.id) {
|
||||
if (data.id && op == "edit") {
|
||||
updateAccess(req);
|
||||
return;
|
||||
}
|
||||
|
||||
245
ui/src/components/certimate/StringList.tsx
Normal file
245
ui/src/components/certimate/StringList.tsx
Normal file
@@ -0,0 +1,245 @@
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
import Show from "../Show";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { FormControl, FormLabel } from "../ui/form";
|
||||
import { Button } from "../ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "../ui/dialog";
|
||||
import { Input } from "../ui/input";
|
||||
import { z } from "zod";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Edit, Plus, Trash2 } from "lucide-react";
|
||||
|
||||
type StringListProps = {
|
||||
className?: string;
|
||||
value: string;
|
||||
valueType?: "domain" | "ip";
|
||||
onValueChange: (value: string) => void;
|
||||
};
|
||||
|
||||
const titles: Record<string, string> = {
|
||||
domain: "domain",
|
||||
ip: "IP",
|
||||
};
|
||||
|
||||
const StringList = ({
|
||||
value,
|
||||
className,
|
||||
onValueChange,
|
||||
valueType = "domain",
|
||||
}: StringListProps) => {
|
||||
const [list, setList] = useState<string[]>([]);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
useMemo(() => {
|
||||
if (value) {
|
||||
setList(value.split(";"));
|
||||
}
|
||||
}, [value]);
|
||||
|
||||
useEffect(() => {
|
||||
const changeList = () => {
|
||||
onValueChange(list.join(";"));
|
||||
};
|
||||
changeList();
|
||||
}, [list]);
|
||||
|
||||
const addVal = (val: string) => {
|
||||
if (list.includes(val)) {
|
||||
return;
|
||||
}
|
||||
setList([...list, val]);
|
||||
};
|
||||
|
||||
const editVal = (index: number, val: string) => {
|
||||
const newList = [...list];
|
||||
newList[index] = val;
|
||||
setList(newList);
|
||||
};
|
||||
|
||||
const onRemoveClick = (index: number) => {
|
||||
const newList = [...list];
|
||||
newList.splice(index, 1);
|
||||
setList(newList);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={cn(className)}>
|
||||
<FormLabel className="flex justify-between items-center">
|
||||
<div>{t(titles[valueType])}</div>
|
||||
|
||||
<Show when={list.length > 0}>
|
||||
<StringEdit
|
||||
op="add"
|
||||
onValueChange={(val: string) => {
|
||||
addVal(val);
|
||||
}}
|
||||
valueType={valueType}
|
||||
value={""}
|
||||
trigger={
|
||||
<div className="flex items-center text-primary">
|
||||
<Plus size={16} className="cursor-pointer " />
|
||||
|
||||
<div className="text-sm ">{t("add")}</div>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</Show>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Show
|
||||
when={list.length > 0}
|
||||
fallback={
|
||||
<div className="border rounded-md p-3 text-sm mt-2 flex flex-col items-center">
|
||||
<div className="text-muted-foreground">暂未添加域名</div>
|
||||
|
||||
<StringEdit
|
||||
value={""}
|
||||
trigger={t("add")}
|
||||
onValueChange={addVal}
|
||||
valueType={valueType}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div className="border rounded-md p-3 text-sm mt-2 text-gray-700 space-y-2 dark:text-white dark:border-stone-700 dark:bg-stone-950">
|
||||
{list.map((item, index) => (
|
||||
<div key={index} className="flex justify-between items-center">
|
||||
<div>{item}</div>
|
||||
<div className="flex space-x-2">
|
||||
<StringEdit
|
||||
op="edit"
|
||||
valueType={valueType}
|
||||
trigger={
|
||||
<Edit
|
||||
size={16}
|
||||
className="cursor-pointer text-gray-600 dark:text-white"
|
||||
/>
|
||||
}
|
||||
value={item}
|
||||
onValueChange={(val: string) => {
|
||||
editVal(index, val);
|
||||
}}
|
||||
/>
|
||||
<Trash2
|
||||
size={16}
|
||||
className="cursor-pointer"
|
||||
onClick={() => {
|
||||
onRemoveClick(index);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Show>
|
||||
</FormControl>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default StringList;
|
||||
|
||||
type ValueType = "domain" | "ip";
|
||||
|
||||
type StringEditProps = {
|
||||
value: string;
|
||||
trigger: React.ReactNode;
|
||||
onValueChange: (value: string) => void;
|
||||
valueType: ValueType;
|
||||
op?: "add" | "edit";
|
||||
};
|
||||
|
||||
const StringEdit = ({
|
||||
trigger,
|
||||
value,
|
||||
onValueChange,
|
||||
op = "add",
|
||||
valueType,
|
||||
}: StringEditProps) => {
|
||||
const [currentValue, setCurrentValue] = useState<string>("");
|
||||
const [open, setOpen] = useState<boolean>(false);
|
||||
const [error, setError] = useState<string>("");
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentValue(value);
|
||||
}, [value]);
|
||||
|
||||
const domainSchema = z
|
||||
.string()
|
||||
.regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
|
||||
message: t("domain.not.empty.verify.message"),
|
||||
});
|
||||
|
||||
const ipSchema = z.string().ip({ message: t("ip.not.empty.verify.message") });
|
||||
|
||||
const schedules: Record<ValueType, z.ZodString> = {
|
||||
domain: domainSchema,
|
||||
ip: ipSchema,
|
||||
};
|
||||
|
||||
const onSaveClick = useCallback(() => {
|
||||
const schema = schedules[valueType];
|
||||
|
||||
const resp = schema.safeParse(currentValue);
|
||||
if (!resp.success) {
|
||||
setError(JSON.parse(resp.error.message)[0].message);
|
||||
return;
|
||||
}
|
||||
|
||||
setCurrentValue("");
|
||||
setOpen(false);
|
||||
setError("");
|
||||
|
||||
onValueChange(currentValue);
|
||||
}, [currentValue]);
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={open}
|
||||
onOpenChange={(open) => {
|
||||
setOpen(open);
|
||||
}}
|
||||
>
|
||||
<DialogTrigger className="text-primary">{trigger}</DialogTrigger>
|
||||
<DialogContent className="dark:text-white">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="dark:text-white">
|
||||
{t(titles[valueType])}
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<Input
|
||||
value={currentValue}
|
||||
className="dark:text-white"
|
||||
onChange={(e) => {
|
||||
setCurrentValue(e.target.value);
|
||||
}}
|
||||
/>
|
||||
<Show when={error.length > 0}>
|
||||
<div className="text-red-500 text-sm">{error}</div>
|
||||
</Show>
|
||||
|
||||
<DialogFooter>
|
||||
<Button
|
||||
onClick={() => {
|
||||
onSaveClick();
|
||||
}}
|
||||
>
|
||||
{op === "add" ? t("add") : t("confirm")}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
@@ -1,15 +1,16 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const accessTypeMap: Map<string, [string, string]> = new Map([
|
||||
["tencent", ["tencent", "/imgs/providers/tencent.svg"]],
|
||||
["aliyun", ["aliyun", "/imgs/providers/aliyun.svg"]],
|
||||
["tencent", ["tencent", "/imgs/providers/tencent.svg"]],
|
||||
["huaweicloud", ["huaweicloud", "/imgs/providers/huaweicloud.svg"]],
|
||||
["qiniu", ["qiniu", "/imgs/providers/qiniu.svg"]],
|
||||
["cloudflare", ["cloudflare", "/imgs/providers/cloudflare.svg"]],
|
||||
["namesilo", ["namesilo", "/imgs/providers/namesilo.svg"]],
|
||||
["godaddy", ["go.daddy", "/imgs/providers/godaddy.svg"]],
|
||||
["qiniu", ["qiniu", "/imgs/providers/qiniu.svg"]],
|
||||
["local", ["local.deployment", "/imgs/providers/local.svg"]],
|
||||
["ssh", ["ssh", "/imgs/providers/ssh.svg"]],
|
||||
["webhook", ["webhook", "/imgs/providers/webhook.svg"]],
|
||||
["local", ["local.deployment", "/imgs/providers/local.svg"]],
|
||||
]);
|
||||
|
||||
export const getProviderInfo = (t: string) => {
|
||||
@@ -20,13 +21,14 @@ export const accessFormType = z.union(
|
||||
[
|
||||
z.literal("aliyun"),
|
||||
z.literal("tencent"),
|
||||
z.literal("ssh"),
|
||||
z.literal("webhook"),
|
||||
z.literal("cloudflare"),
|
||||
z.literal("huaweicloud"),
|
||||
z.literal("qiniu"),
|
||||
z.literal("cloudflare"),
|
||||
z.literal("namesilo"),
|
||||
z.literal("godaddy"),
|
||||
z.literal("local"),
|
||||
z.literal("ssh"),
|
||||
z.literal("webhook"),
|
||||
],
|
||||
{ message: "access.not.empty" }
|
||||
);
|
||||
@@ -40,52 +42,61 @@ export type Access = {
|
||||
usage: AccessUsage;
|
||||
group?: string;
|
||||
config:
|
||||
| TencentConfig
|
||||
| AliyunConfig
|
||||
| SSHConfig
|
||||
| WebhookConfig
|
||||
| CloudflareConfig
|
||||
| TencentConfig
|
||||
| HuaweicloudConfig
|
||||
| QiniuConfig
|
||||
| CloudflareConfig
|
||||
| NamesiloConfig
|
||||
| GodaddyConfig
|
||||
| LocalConfig;
|
||||
|
||||
| LocalConfig
|
||||
| SSHConfig
|
||||
| WebhookConfig;
|
||||
deleted?: string;
|
||||
created?: string;
|
||||
updated?: string;
|
||||
};
|
||||
|
||||
export type QiniuConfig = {
|
||||
accessKey: string;
|
||||
secretKey: string;
|
||||
};
|
||||
|
||||
export type WebhookConfig = {
|
||||
url: string;
|
||||
};
|
||||
|
||||
export type CloudflareConfig = {
|
||||
dnsApiToken: string;
|
||||
};
|
||||
|
||||
export type TencentConfig = {
|
||||
secretId: string;
|
||||
secretKey: string;
|
||||
};
|
||||
|
||||
export type AliyunConfig = {
|
||||
accessKeyId: string;
|
||||
accessKeySecret: string;
|
||||
};
|
||||
|
||||
export type TencentConfig = {
|
||||
secretId: string;
|
||||
secretKey: string;
|
||||
};
|
||||
|
||||
export type HuaweicloudConfig = {
|
||||
region: string;
|
||||
accessKeyId: string;
|
||||
secretAccessKey: string;
|
||||
};
|
||||
|
||||
export type QiniuConfig = {
|
||||
accessKey: string;
|
||||
secretKey: string;
|
||||
};
|
||||
|
||||
export type CloudflareConfig = {
|
||||
dnsApiToken: string;
|
||||
};
|
||||
|
||||
export type NamesiloConfig = {
|
||||
apiKey: string;
|
||||
};
|
||||
|
||||
export type GodaddyConfig = {
|
||||
apiKey: string;
|
||||
apiSecret: string;
|
||||
};
|
||||
|
||||
export type LocalConfig = {
|
||||
command: string;
|
||||
certPath: string;
|
||||
keyPath: string;
|
||||
};
|
||||
|
||||
export type SSHConfig = {
|
||||
host: string;
|
||||
port: string;
|
||||
@@ -99,27 +110,28 @@ export type SSHConfig = {
|
||||
keyPath: string;
|
||||
};
|
||||
|
||||
export type LocalConfig = {
|
||||
command: string;
|
||||
certPath: string;
|
||||
keyPath: string;
|
||||
export type WebhookConfig = {
|
||||
url: string;
|
||||
};
|
||||
|
||||
export const getUsageByConfigType = (configType: string): AccessUsage => {
|
||||
switch (configType) {
|
||||
case "aliyun":
|
||||
case "tencent":
|
||||
case "huaweicloud":
|
||||
return "all";
|
||||
case "ssh":
|
||||
case "webhook":
|
||||
|
||||
case "qiniu":
|
||||
case "local":
|
||||
case "ssh":
|
||||
case "webhook":
|
||||
return "deploy";
|
||||
|
||||
case "cloudflare":
|
||||
case "namesilo":
|
||||
case "godaddy":
|
||||
return "apply";
|
||||
|
||||
default:
|
||||
return "all";
|
||||
}
|
||||
|
||||
@@ -26,6 +26,22 @@ export type Domain = {
|
||||
expand?: {
|
||||
lastDeployment?: Deployment;
|
||||
};
|
||||
|
||||
applyConfig?: ApplyConfig;
|
||||
deployConfig?: DeployConfig[];
|
||||
};
|
||||
|
||||
export type DeployConfig = {
|
||||
access: string;
|
||||
type: string;
|
||||
config?: Record<string, string>;
|
||||
};
|
||||
|
||||
export type ApplyConfig = {
|
||||
access: string;
|
||||
email: string;
|
||||
timeout?: number;
|
||||
nameservers?: string;
|
||||
};
|
||||
|
||||
export type Statistic = {
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const version = "Certimate v0.1.14";
|
||||
export const version = "Certimate v0.1.19";
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"cancel": "Cancel",
|
||||
"confirm": "Confirm",
|
||||
"edit": "Edit",
|
||||
"copy": "Copy",
|
||||
"succeed": "Successful",
|
||||
"add": "Add",
|
||||
"document": "Document",
|
||||
@@ -49,6 +50,7 @@
|
||||
"aliyun.cdn": "Alibaba Cloud-CDN",
|
||||
"aliyun.oss": "Alibaba Cloud-OSS",
|
||||
"aliyun.dcdn": "Alibaba Cloud-DCDN",
|
||||
"huaweicloud": "Huawei Cloud",
|
||||
"qiniu": "Qiniu",
|
||||
"qiniu.cdn": "Qiniu-CDN",
|
||||
"cloudflare": "Cloudflare",
|
||||
@@ -82,6 +84,7 @@
|
||||
"pagination.prev": "Previous",
|
||||
"domain": "Domain",
|
||||
"domain.add": "Add Domain",
|
||||
"domain.edit":"Edit Domain",
|
||||
"domain.delete": "Delete Domain",
|
||||
"domain.not.empty.verify.message": "Please enter domain",
|
||||
"domain.management.name": "Domain List",
|
||||
@@ -154,6 +157,8 @@
|
||||
"access.management": "Authorization Management",
|
||||
"access.add": "Add Authorization",
|
||||
"access.edit": "Edit Authorization",
|
||||
"access.copy": "Copy Authorization",
|
||||
"access.delete.confirm": "Are you sure you want to delete the deployment authorization?",
|
||||
"access.all": "All Authorizations",
|
||||
"access.list": "Authorization List",
|
||||
"access.type": "Provider",
|
||||
@@ -190,6 +195,8 @@
|
||||
"access.form.secret.key.not.empty": "Please enter SecretKey",
|
||||
"access.form.access.key": "AccessKey",
|
||||
"access.form.access.key.not.empty": "Please enter AccessKey",
|
||||
"access.form.region": "Region",
|
||||
"access.form.region.not.empty": "Please enter Region",
|
||||
"access.form.webhook.url": "Webhook URL",
|
||||
"access.form.webhook.url.not.empty": "Please enter Webhook URL",
|
||||
"access.form.ssh.group.label": "Authorization Configuration Group (used to deploy a single domain certificate to multiple SSH hosts)",
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"cancel": "取消",
|
||||
"confirm": "确认",
|
||||
"edit": "编辑",
|
||||
"copy": "复制",
|
||||
"succeed": "成功",
|
||||
"add": "新增",
|
||||
"document": "文档",
|
||||
@@ -49,6 +50,7 @@
|
||||
"aliyun.cdn": "阿里云-CDN",
|
||||
"aliyun.oss": "阿里云-OSS",
|
||||
"aliyun.dcdn": "阿里云-DCDN",
|
||||
"huaweicloud": "华为云",
|
||||
"qiniu": "七牛云",
|
||||
"qiniu.cdn": "七牛云-CDN",
|
||||
"cloudflare": "Cloudflare",
|
||||
@@ -82,6 +84,7 @@
|
||||
"pagination.prev": "上一页",
|
||||
"domain": "域名",
|
||||
"domain.add": "新增域名",
|
||||
"domain.edit": "编辑域名",
|
||||
"domain.delete": "删除域名",
|
||||
"domain.not.empty.verify.message": "请输入域名",
|
||||
"domain.management.name": "域名列表",
|
||||
@@ -154,6 +157,8 @@
|
||||
"access.management": "授权管理",
|
||||
"access.add": "添加授权",
|
||||
"access.edit": "编辑授权",
|
||||
"access.copy": "复制授权",
|
||||
"access.delete.confirm": "确定要删除授权吗?",
|
||||
"access.all": "所有授权",
|
||||
"access.list": "授权列表",
|
||||
"access.type": "服务商",
|
||||
@@ -190,6 +195,8 @@
|
||||
"access.form.secret.key.not.empty": "请输入 SecretKey",
|
||||
"access.form.access.key": "AccessKey",
|
||||
"access.form.access.key.not.empty": "请输入 AccessKey",
|
||||
"access.form.region": "Region",
|
||||
"access.form.region.not.empty": "请输入区域",
|
||||
"access.form.webhook.url": "Webhook URL",
|
||||
"access.form.webhook.url.not.empty": "请输入 Webhook URL",
|
||||
"access.form.ssh.group.label": "授权配置组(用于将一个域名证书部署到多个 ssh 主机)",
|
||||
|
||||
@@ -12,6 +12,15 @@ import { remove } from "@/repository/access";
|
||||
import { t } from "i18next";
|
||||
import { Key } from "lucide-react";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent, AlertDialogDescription, AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger
|
||||
} from "@/components/ui/alert-dialog.tsx";
|
||||
|
||||
const Access = () => {
|
||||
const { config, deleteAccess } = useConfig();
|
||||
@@ -149,15 +158,45 @@ const Access = () => {
|
||||
data={access}
|
||||
/>
|
||||
<Separator orientation="vertical" className="h-4 mx-2" />
|
||||
<Button
|
||||
variant={"link"}
|
||||
className="p-0"
|
||||
onClick={() => {
|
||||
handleDelete(access);
|
||||
}}
|
||||
>
|
||||
{t("delete")}
|
||||
</Button>
|
||||
<AccessEdit
|
||||
trigger={
|
||||
<Button variant={"link"} className="p-0">
|
||||
{t("copy")}
|
||||
</Button>
|
||||
}
|
||||
op="copy"
|
||||
data={access}
|
||||
/>
|
||||
<Separator orientation="vertical" className="h-4 mx-2" />
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<Button variant={"link"} size={"sm"}>
|
||||
{t('delete')}
|
||||
</Button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle className="dark:text-gray-200">
|
||||
{t('access.group.delete')}
|
||||
</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
{t('access.delete.confirm')}
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel className="dark:text-gray-200">
|
||||
{t('cancel')}
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
onClick={() => {
|
||||
handleDelete(access);
|
||||
}}
|
||||
>
|
||||
{t('confirm')}
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -57,7 +57,7 @@ const Dashboard = () => {
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
<div className="flex justify-between items-center">
|
||||
<div className="text-muted-foreground">{t('dashboard')}</div>
|
||||
<div className="text-muted-foreground">{t("dashboard")}</div>
|
||||
</div>
|
||||
<div className="flex mt-10 gap-5 flex-col flex-wrap md:flex-row">
|
||||
<div className="w-full md:w-[250px] 3xl:w-[300px] flex items-center rounded-md p-3 shadow-lg border">
|
||||
@@ -66,7 +66,7 @@ const Dashboard = () => {
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-muted-foreground font-semibold">
|
||||
{t('dashboard.all')}
|
||||
{t("dashboard.all")}
|
||||
</div>
|
||||
<div className="flex items-baseline">
|
||||
<div className="text-3xl text-stone-700 dark:text-stone-200">
|
||||
@@ -91,7 +91,7 @@ const Dashboard = () => {
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-muted-foreground font-semibold">
|
||||
{t('dashboard.near.expired')}
|
||||
{t("dashboard.near.expired")}
|
||||
</div>
|
||||
<div className="flex items-baseline">
|
||||
<div className="text-3xl text-stone-700 dark:text-stone-200">
|
||||
@@ -120,7 +120,7 @@ const Dashboard = () => {
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-muted-foreground font-semibold">
|
||||
{t('dashboard.enabled')}
|
||||
{t("dashboard.enabled")}
|
||||
</div>
|
||||
<div className="flex items-baseline">
|
||||
<div className="text-3xl text-stone-700 dark:text-stone-200">
|
||||
@@ -144,7 +144,9 @@ const Dashboard = () => {
|
||||
<Ban size={48} strokeWidth={1} className="text-gray-400" />
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-muted-foreground font-semibold">{t('dashboard.not.enabled')}</div>
|
||||
<div className="text-muted-foreground font-semibold">
|
||||
{t("dashboard.not.enabled")}
|
||||
</div>
|
||||
<div className="flex items-baseline">
|
||||
<div className="text-3xl text-stone-700 dark:text-stone-200">
|
||||
{statistic?.disabled ? (
|
||||
@@ -168,22 +170,19 @@ const Dashboard = () => {
|
||||
|
||||
<div>
|
||||
<div className="text-muted-foreground mt-5 text-sm">
|
||||
{t('deployment.log.name')}
|
||||
{t("deployment.log.name")}
|
||||
</div>
|
||||
|
||||
{deployments?.length == 0 ? (
|
||||
<>
|
||||
<Alert className="max-w-[40em] mt-10">
|
||||
<AlertTitle>{t('no.data')}</AlertTitle>
|
||||
<AlertTitle>{t("no.data")}</AlertTitle>
|
||||
<AlertDescription>
|
||||
<div className="flex items-center mt-5">
|
||||
<div>
|
||||
<Smile className="text-yellow-400" size={36} />
|
||||
</div>
|
||||
<div className="ml-2">
|
||||
{" "}
|
||||
{t('deployment.log.empty')}
|
||||
</div>
|
||||
<div className="ml-2"> {t("deployment.log.empty")}</div>
|
||||
</div>
|
||||
<div className="mt-2 flex justify-end">
|
||||
<Button
|
||||
@@ -191,7 +190,7 @@ const Dashboard = () => {
|
||||
navigate("/edit");
|
||||
}}
|
||||
>
|
||||
{t('domain.add')}
|
||||
{t("domain.add")}
|
||||
</Button>
|
||||
</div>
|
||||
</AlertDescription>
|
||||
@@ -200,16 +199,18 @@ const Dashboard = () => {
|
||||
) : (
|
||||
<>
|
||||
<div className="hidden sm:flex sm:flex-row text-muted-foreground text-sm border-b dark:border-stone-500 sm:p-2 mt-5">
|
||||
<div className="w-48">{t('domain')}</div>
|
||||
<div className="w-48">{t("domain")}</div>
|
||||
|
||||
<div className="w-24">{t('deployment.log.status')}</div>
|
||||
<div className="w-56">{t('deployment.log.stage')}</div>
|
||||
<div className="w-56 sm:ml-2 text-center">{t('deployment.log.last.execution.time')}</div>
|
||||
<div className="w-24">{t("deployment.log.status")}</div>
|
||||
<div className="w-56">{t("deployment.log.stage")}</div>
|
||||
<div className="w-56 sm:ml-2 text-center">
|
||||
{t("deployment.log.last.execution.time")}
|
||||
</div>
|
||||
|
||||
<div className="grow">{t('operation')}</div>
|
||||
<div className="grow">{t("operation")}</div>
|
||||
</div>
|
||||
<div className="sm:hidden flex text-sm text-muted-foreground">
|
||||
{t('deployment.log.name')}
|
||||
{t("deployment.log.name")}
|
||||
</div>
|
||||
|
||||
{deployments?.map((deployment) => (
|
||||
@@ -218,7 +219,14 @@ const Dashboard = () => {
|
||||
className="flex flex-col sm:flex-row text-secondary-foreground border-b dark:border-stone-500 sm:p-2 hover:bg-muted/50 text-sm"
|
||||
>
|
||||
<div className="sm:w-48 w-full pt-1 sm:pt-0 flex items-center">
|
||||
{deployment.expand.domain?.domain}
|
||||
{deployment.expand.domain?.domain
|
||||
.split(";")
|
||||
.map((domain: string) => (
|
||||
<>
|
||||
{domain}
|
||||
<br />
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
<div className="sm:w-24 w-full pt-1 sm:pt-0 flex items-center">
|
||||
<DeployState deployment={deployment} />
|
||||
@@ -236,14 +244,14 @@ const Dashboard = () => {
|
||||
<Sheet>
|
||||
<SheetTrigger asChild>
|
||||
<Button variant={"link"} className="p-0">
|
||||
{t('deployment.log.detail.button.text')}
|
||||
{t("deployment.log.detail.button.text")}
|
||||
</Button>
|
||||
</SheetTrigger>
|
||||
<SheetContent className="sm:max-w-5xl">
|
||||
<SheetHeader>
|
||||
<SheetTitle>
|
||||
{deployment.expand.domain?.domain}-{deployment.id}
|
||||
{t('deployment.log.detail')}
|
||||
{t("deployment.log.detail")}
|
||||
</SheetTitle>
|
||||
</SheetHeader>
|
||||
<div className="bg-gray-950 text-stone-100 p-5 text-sm h-[80dvh]">
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { useForm } from "react-hook-form";
|
||||
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
@@ -39,6 +38,7 @@ import { Textarea } from "@/components/ui/textarea";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { EmailsSetting } from "@/domain/settings";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import StringList from "@/components/certimate/StringList";
|
||||
|
||||
const Edit = () => {
|
||||
const {
|
||||
@@ -70,16 +70,16 @@ const Edit = () => {
|
||||
|
||||
const formSchema = z.object({
|
||||
id: z.string().optional(),
|
||||
domain: z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
|
||||
message: 'domain.not.empty.verify.message',
|
||||
domain: z.string().min(1, {
|
||||
message: "domain.not.empty.verify.message",
|
||||
}),
|
||||
email: z.string().email('email.valid.message').optional(),
|
||||
email: z.string().email("email.valid.message").optional(),
|
||||
access: z.string().regex(/^[a-zA-Z0-9]+$/, {
|
||||
message: 'domain.management.edit.dns.access.not.empty.message',
|
||||
message: "domain.management.edit.dns.access.not.empty.message",
|
||||
}),
|
||||
targetAccess: z.string().optional(),
|
||||
targetType: z.string().regex(/^[a-zA-Z0-9-]+$/, {
|
||||
message: 'domain.management.edit.target.type.not.empty.message',
|
||||
message: "domain.management.edit.target.type.not.empty.message",
|
||||
}),
|
||||
variables: z.string().optional(),
|
||||
group: z.string().optional(),
|
||||
@@ -140,11 +140,11 @@ const Edit = () => {
|
||||
if (group == "" && targetAccess == "") {
|
||||
form.setError("group", {
|
||||
type: "manual",
|
||||
message: 'domain.management.edit.target.access.verify.msg',
|
||||
message: "domain.management.edit.target.access.verify.msg",
|
||||
});
|
||||
form.setError("targetAccess", {
|
||||
type: "manual",
|
||||
message: 'domain.management.edit.target.access.verify.msg',
|
||||
message: "domain.management.edit.target.access.verify.msg",
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -164,13 +164,13 @@ const Edit = () => {
|
||||
|
||||
try {
|
||||
await save(req);
|
||||
let description = t('domain.management.edit.succeed.tips');
|
||||
let description = t("domain.management.edit.succeed.tips");
|
||||
if (req.id == "") {
|
||||
description = t('domain.management.add.succeed.tips');
|
||||
description = t("domain.management.add.succeed.tips");
|
||||
}
|
||||
|
||||
toast({
|
||||
title: t('succeed'),
|
||||
title: t("succeed"),
|
||||
description,
|
||||
});
|
||||
navigate("/domains");
|
||||
@@ -195,7 +195,7 @@ const Edit = () => {
|
||||
<div className="">
|
||||
<Toaster />
|
||||
<div className=" h-5 text-muted-foreground">
|
||||
{domain?.id ? t('domain.edit') : t('domain.add')}
|
||||
{domain?.id ? t("domain.edit") : t("domain.add")}
|
||||
</div>
|
||||
<div className="mt-5 flex w-full justify-center md:space-x-10 flex-col md:flex-row">
|
||||
<div className="w-full md:w-[200px] text-muted-foreground space-x-3 md:space-y-3 flex-row md:flex-col flex">
|
||||
@@ -208,7 +208,7 @@ const Edit = () => {
|
||||
setTab("base");
|
||||
}}
|
||||
>
|
||||
{t('basic.setting')}
|
||||
{t("basic.setting")}
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
@@ -219,7 +219,7 @@ const Edit = () => {
|
||||
setTab("advance");
|
||||
}}
|
||||
>
|
||||
{t('advanced.setting')}
|
||||
{t("advanced.setting")}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -234,10 +234,15 @@ const Edit = () => {
|
||||
name="domain"
|
||||
render={({ field }) => (
|
||||
<FormItem hidden={tab != "base"}>
|
||||
<FormLabel>{t('domain')}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t('domain.not.empty.verify.message')} {...field} />
|
||||
</FormControl>
|
||||
<>
|
||||
<StringList
|
||||
value={field.value}
|
||||
valueType="domain"
|
||||
onValueChange={(domain: string) => {
|
||||
form.setValue("domain", domain);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@@ -249,12 +254,15 @@ const Edit = () => {
|
||||
render={({ field }) => (
|
||||
<FormItem hidden={tab != "base"}>
|
||||
<FormLabel className="flex w-full justify-between">
|
||||
<div>{t('email') + t('domain.management.edit.email.description')}</div>
|
||||
<div>
|
||||
{t("email") +
|
||||
t("domain.management.edit.email.description")}
|
||||
</div>
|
||||
<EmailsEdit
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t('add')}
|
||||
{t("add")}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
@@ -268,11 +276,15 @@ const Edit = () => {
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t('domain.management.edit.email.not.empty.message')} />
|
||||
<SelectValue
|
||||
placeholder={t(
|
||||
"domain.management.edit.email.not.empty.message"
|
||||
)}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectLabel>{t('email.list')}</SelectLabel>
|
||||
<SelectLabel>{t("email.list")}</SelectLabel>
|
||||
{(emails.content as EmailsSetting).emails.map(
|
||||
(item) => (
|
||||
<SelectItem key={item} value={item}>
|
||||
@@ -295,12 +307,14 @@ const Edit = () => {
|
||||
render={({ field }) => (
|
||||
<FormItem hidden={tab != "base"}>
|
||||
<FormLabel className="flex w-full justify-between">
|
||||
<div>{t('domain.management.edit.dns.access.label')}</div>
|
||||
<div>
|
||||
{t("domain.management.edit.dns.access.label")}
|
||||
</div>
|
||||
<AccessEdit
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t('add')}
|
||||
{t("add")}
|
||||
</div>
|
||||
}
|
||||
op="add"
|
||||
@@ -315,11 +329,17 @@ const Edit = () => {
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t('domain.management.edit.access.not.empty.message')} />
|
||||
<SelectValue
|
||||
placeholder={t(
|
||||
"domain.management.edit.access.not.empty.message"
|
||||
)}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectLabel>{t('domain.management.edit.access.label')}</SelectLabel>
|
||||
<SelectLabel>
|
||||
{t("domain.management.edit.access.label")}
|
||||
</SelectLabel>
|
||||
{accesses
|
||||
.filter((item) => item.usage != "deploy")
|
||||
.map((item) => (
|
||||
@@ -351,7 +371,9 @@ const Edit = () => {
|
||||
name="targetType"
|
||||
render={({ field }) => (
|
||||
<FormItem hidden={tab != "base"}>
|
||||
<FormLabel>{t('domain.management.edit.target.type')}</FormLabel>
|
||||
<FormLabel>
|
||||
{t("domain.management.edit.target.type")}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
{...field}
|
||||
@@ -361,11 +383,17 @@ const Edit = () => {
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t('domain.management.edit.target.type.not.empty.message')} />
|
||||
<SelectValue
|
||||
placeholder={t(
|
||||
"domain.management.edit.target.type.not.empty.message"
|
||||
)}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectLabel>{t('domain.management.edit.target.type')}</SelectLabel>
|
||||
<SelectLabel>
|
||||
{t("domain.management.edit.target.type")}
|
||||
</SelectLabel>
|
||||
{targetTypeKeys.map((key) => (
|
||||
<SelectItem key={key} value={key}>
|
||||
<div className="flex items-center space-x-2">
|
||||
@@ -373,7 +401,9 @@ const Edit = () => {
|
||||
className="w-6"
|
||||
src={targetTypeMap.get(key)?.[1]}
|
||||
/>
|
||||
<div>{t(targetTypeMap.get(key)?.[0] || '')}</div>
|
||||
<div>
|
||||
{t(targetTypeMap.get(key)?.[0] || "")}
|
||||
</div>
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
@@ -392,12 +422,12 @@ const Edit = () => {
|
||||
render={({ field }) => (
|
||||
<FormItem hidden={tab != "base"}>
|
||||
<FormLabel className="w-full flex justify-between">
|
||||
<div>{t('domain.management.edit.target.access')}</div>
|
||||
<div>{t("domain.management.edit.target.access")}</div>
|
||||
<AccessEdit
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t('add')}
|
||||
{t("add")}
|
||||
</div>
|
||||
}
|
||||
op="add"
|
||||
@@ -411,12 +441,19 @@ const Edit = () => {
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t('domain.management.edit.target.access.not.empty.message')} />
|
||||
<SelectValue
|
||||
placeholder={t(
|
||||
"domain.management.edit.target.access.not.empty.message"
|
||||
)}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectLabel>
|
||||
{t('domain.management.edit.target.access.content.label')} {form.getValues().targetAccess}
|
||||
{t(
|
||||
"domain.management.edit.target.access.content.label"
|
||||
)}{" "}
|
||||
{form.getValues().targetAccess}
|
||||
</SelectLabel>
|
||||
<SelectItem value="emptyId">
|
||||
<div className="flex items-center space-x-2">
|
||||
@@ -452,9 +489,7 @@ const Edit = () => {
|
||||
render={({ field }) => (
|
||||
<FormItem hidden={tab != "advance" || targetType != "ssh"}>
|
||||
<FormLabel className="w-full flex justify-between">
|
||||
<div>
|
||||
{t('domain.management.edit.group.label')}
|
||||
</div>
|
||||
<div>{t("domain.management.edit.group.label")}</div>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
@@ -466,7 +501,11 @@ const Edit = () => {
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t('domain.management.edit.group.not.empty.message')} />
|
||||
<SelectValue
|
||||
placeholder={t(
|
||||
"domain.management.edit.group.not.empty.message"
|
||||
)}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="emptyId">
|
||||
@@ -511,10 +550,12 @@ const Edit = () => {
|
||||
name="variables"
|
||||
render={({ field }) => (
|
||||
<FormItem hidden={tab != "advance"}>
|
||||
<FormLabel>{t('variables')}</FormLabel>
|
||||
<FormLabel>{t("variables")}</FormLabel>
|
||||
<FormControl>
|
||||
<Textarea
|
||||
placeholder={t('domain.management.edit.variables.placeholder')}
|
||||
placeholder={t(
|
||||
"domain.management.edit.variables.placeholder"
|
||||
)}
|
||||
{...field}
|
||||
className="placeholder:whitespace-pre-wrap"
|
||||
/>
|
||||
@@ -530,10 +571,12 @@ const Edit = () => {
|
||||
name="nameservers"
|
||||
render={({ field }) => (
|
||||
<FormItem hidden={tab != "advance"}>
|
||||
<FormLabel>{t('dns')}</FormLabel>
|
||||
<FormLabel>{t("dns")}</FormLabel>
|
||||
<FormControl>
|
||||
<Textarea
|
||||
placeholder={t('domain.management.edit.dns.placeholder')}
|
||||
placeholder={t(
|
||||
"domain.management.edit.dns.placeholder"
|
||||
)}
|
||||
{...field}
|
||||
className="placeholder:whitespace-pre-wrap"
|
||||
/>
|
||||
@@ -545,7 +588,7 @@ const Edit = () => {
|
||||
/>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t('save')}</Button>
|
||||
<Button type="submit">{t("save")}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
|
||||
@@ -41,7 +41,7 @@ const Home = () => {
|
||||
const toast = useToast();
|
||||
|
||||
const navigate = useNavigate();
|
||||
const { t } = useTranslation()
|
||||
const { t } = useTranslation();
|
||||
|
||||
const location = useLocation();
|
||||
const query = new URLSearchParams(location.search);
|
||||
@@ -129,12 +129,12 @@ const Home = () => {
|
||||
await save(domain);
|
||||
|
||||
toast.toast({
|
||||
title: t('operation.succeed'),
|
||||
description: t('domain.management.start.deploy.succeed.tips'),
|
||||
title: t("operation.succeed"),
|
||||
description: t("domain.management.start.deploy.succeed.tips"),
|
||||
});
|
||||
} catch (e) {
|
||||
toast.toast({
|
||||
title: t('domain.management.execution.failed'),
|
||||
title: t("domain.management.execution.failed"),
|
||||
description: (
|
||||
// 这里的 text 只是占位作用,实际文案在 src/i18n/locales/[lang].json
|
||||
<Trans i18nKey="domain.management.execution.failed.tips">
|
||||
@@ -142,7 +142,9 @@ const Home = () => {
|
||||
<Link
|
||||
to={`/history?domain=${domain.id}`}
|
||||
className="underline text-blue-500"
|
||||
>text2</Link>
|
||||
>
|
||||
text2
|
||||
</Link>
|
||||
text3
|
||||
</Trans>
|
||||
),
|
||||
@@ -176,10 +178,10 @@ const Home = () => {
|
||||
<div className="">
|
||||
<Toaster />
|
||||
<div className="flex justify-between items-center">
|
||||
<div className="text-muted-foreground">{t('domain.management.name')}</div>
|
||||
<Button onClick={handleCreateClick}>
|
||||
{t('domain.add')}
|
||||
</Button>
|
||||
<div className="text-muted-foreground">
|
||||
{t("domain.management.name")}
|
||||
</div>
|
||||
<Button onClick={handleCreateClick}>{t("domain.add")}</Button>
|
||||
</div>
|
||||
|
||||
{!domains.length ? (
|
||||
@@ -190,26 +192,32 @@ const Home = () => {
|
||||
</span>
|
||||
|
||||
<div className="text-center text-sm text-muted-foreground mt-3">
|
||||
{t('domain.management.empty')}
|
||||
{t("domain.management.empty")}
|
||||
</div>
|
||||
<Button onClick={handleCreateClick} className="mt-3">
|
||||
{t('domain.add')}
|
||||
{t("domain.add")}
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="hidden sm:flex sm:flex-row text-muted-foreground text-sm border-b dark:border-stone-500 sm:p-2 mt-5">
|
||||
<div className="w-36">{t('domain')}</div>
|
||||
<div className="w-40">{t('domain.management.expiry.date')}</div>
|
||||
<div className="w-32">{t('domain.management.last.execution.status')}</div>
|
||||
<div className="w-64">{t('domain.management.last.execution.stage')}</div>
|
||||
<div className="w-40 sm:ml-2">{t('domain.management.last.execution.time')}</div>
|
||||
<div className="w-24">{t('domain.management.enable')}</div>
|
||||
<div className="grow">{t('operation')}</div>
|
||||
<div className="w-36">{t("domain")}</div>
|
||||
<div className="w-40">{t("domain.management.expiry.date")}</div>
|
||||
<div className="w-32">
|
||||
{t("domain.management.last.execution.status")}
|
||||
</div>
|
||||
<div className="w-64">
|
||||
{t("domain.management.last.execution.stage")}
|
||||
</div>
|
||||
<div className="w-40 sm:ml-2">
|
||||
{t("domain.management.last.execution.time")}
|
||||
</div>
|
||||
<div className="w-24">{t("domain.management.enable")}</div>
|
||||
<div className="grow">{t("operation")}</div>
|
||||
</div>
|
||||
<div className="sm:hidden flex text-sm text-muted-foreground">
|
||||
{t('domain')}
|
||||
{t("domain")}
|
||||
</div>
|
||||
|
||||
{domains.map((domain) => (
|
||||
@@ -217,15 +225,26 @@ const Home = () => {
|
||||
className="flex flex-col sm:flex-row text-secondary-foreground border-b dark:border-stone-500 sm:p-2 hover:bg-muted/50 text-sm"
|
||||
key={domain.id}
|
||||
>
|
||||
<div className="sm:w-36 w-full pt-1 sm:pt-0 flex items-center">
|
||||
{domain.domain}
|
||||
<div className="sm:w-36 w-full pt-1 sm:pt-0 flex items-center truncate">
|
||||
{domain.domain.split(";").map((item) => (
|
||||
<>
|
||||
{item}
|
||||
<br />
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
<div className="sm:w-40 w-full pt-1 sm:pt-0 flex items-center">
|
||||
<div>
|
||||
{domain.expiredAt ? (
|
||||
<>
|
||||
<div>{t('domain.management.expiry.date1', { date: 90 })}</div>
|
||||
<div>{t('domain.management.expiry.date2', { date: getDate(domain.expiredAt) })}</div>
|
||||
<div>
|
||||
{t("domain.management.expiry.date1", { date: 90 })}
|
||||
</div>
|
||||
<div>
|
||||
{t("domain.management.expiry.date2", {
|
||||
date: getDate(domain.expiredAt),
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
"---"
|
||||
@@ -269,7 +288,7 @@ const Home = () => {
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<div className="border rounded-sm px-3 bg-background text-muted-foreground text-xs">
|
||||
{domain.enabled ? t('disable') : t('enable')}
|
||||
{domain.enabled ? t("disable") : t("enable")}
|
||||
</div>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
@@ -281,7 +300,7 @@ const Home = () => {
|
||||
className="p-0"
|
||||
onClick={() => handleHistoryClick(domain.id)}
|
||||
>
|
||||
{t('deployment.log.name')}
|
||||
{t("deployment.log.name")}
|
||||
</Button>
|
||||
<Show when={domain.enabled ? true : false}>
|
||||
<Separator orientation="vertical" className="h-4 mx-2" />
|
||||
@@ -290,7 +309,7 @@ const Home = () => {
|
||||
className="p-0"
|
||||
onClick={() => handleRightNowClick(domain)}
|
||||
>
|
||||
{t('domain.management.start.deploying')}
|
||||
{t("domain.management.start.deploying")}
|
||||
</Button>
|
||||
</Show>
|
||||
|
||||
@@ -307,7 +326,7 @@ const Home = () => {
|
||||
className="p-0"
|
||||
onClick={() => handleForceClick(domain)}
|
||||
>
|
||||
{t('domain.management.forced.deployment')}
|
||||
{t("domain.management.forced.deployment")}
|
||||
</Button>
|
||||
</Show>
|
||||
|
||||
@@ -318,7 +337,7 @@ const Home = () => {
|
||||
className="p-0"
|
||||
onClick={() => handleDownloadClick(domain)}
|
||||
>
|
||||
{t('download')}
|
||||
{t("download")}
|
||||
</Button>
|
||||
</Show>
|
||||
|
||||
@@ -328,24 +347,26 @@ const Home = () => {
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<Button variant={"link"} className="p-0">
|
||||
{t('delete')}
|
||||
{t("delete")}
|
||||
</Button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>{t('domain.delete')}</AlertDialogTitle>
|
||||
<AlertDialogTitle>
|
||||
{t("domain.delete")}
|
||||
</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
{t('domain.management.delete.confirm')}
|
||||
{t("domain.management.delete.confirm")}
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>{t('cancel')}</AlertDialogCancel>
|
||||
<AlertDialogCancel>{t("cancel")}</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
onClick={() => {
|
||||
handleDeleteClick(domain.id);
|
||||
}}
|
||||
>
|
||||
{t('confirm')}
|
||||
{t("confirm")}
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
@@ -357,7 +378,7 @@ const Home = () => {
|
||||
className="p-0"
|
||||
onClick={() => handleEditClick(domain.id)}
|
||||
>
|
||||
{t('edit')}
|
||||
{t("edit")}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -40,20 +40,17 @@ const History = () => {
|
||||
|
||||
return (
|
||||
<ScrollArea className="h-[80vh] overflow-hidden">
|
||||
<div className="text-muted-foreground">{t('deployment.log.name')}</div>
|
||||
<div className="text-muted-foreground">{t("deployment.log.name")}</div>
|
||||
{!deployments?.length ? (
|
||||
<>
|
||||
<Alert className="max-w-[40em] mx-auto mt-20">
|
||||
<AlertTitle>{t('no.data')}</AlertTitle>
|
||||
<AlertTitle>{t("no.data")}</AlertTitle>
|
||||
<AlertDescription>
|
||||
<div className="flex items-center mt-5">
|
||||
<div>
|
||||
<Smile className="text-yellow-400" size={36} />
|
||||
</div>
|
||||
<div className="ml-2">
|
||||
{" "}
|
||||
{t('deployment.log.empty')}
|
||||
</div>
|
||||
<div className="ml-2"> {t("deployment.log.empty")}</div>
|
||||
</div>
|
||||
<div className="mt-2 flex justify-end">
|
||||
<Button
|
||||
@@ -61,7 +58,7 @@ const History = () => {
|
||||
navigate("/");
|
||||
}}
|
||||
>
|
||||
{t('domain.add')}
|
||||
{t("domain.add")}
|
||||
</Button>
|
||||
</div>
|
||||
</AlertDescription>
|
||||
@@ -70,16 +67,18 @@ const History = () => {
|
||||
) : (
|
||||
<>
|
||||
<div className="hidden sm:flex sm:flex-row text-muted-foreground text-sm border-b dark:border-stone-500 sm:p-2 mt-5">
|
||||
<div className="w-48">{t('domain')}</div>
|
||||
<div className="w-48">{t("domain")}</div>
|
||||
|
||||
<div className="w-24">{t('deployment.log.status')}</div>
|
||||
<div className="w-56">{t('deployment.log.stage')}</div>
|
||||
<div className="w-56 sm:ml-2 text-center">{t('deployment.log.last.execution.time')}</div>
|
||||
<div className="w-24">{t("deployment.log.status")}</div>
|
||||
<div className="w-56">{t("deployment.log.stage")}</div>
|
||||
<div className="w-56 sm:ml-2 text-center">
|
||||
{t("deployment.log.last.execution.time")}
|
||||
</div>
|
||||
|
||||
<div className="grow">{t('operation')}</div>
|
||||
<div className="grow">{t("operation")}</div>
|
||||
</div>
|
||||
<div className="sm:hidden flex text-sm text-muted-foreground">
|
||||
{t('deployment.log.name')}
|
||||
{t("deployment.log.name")}
|
||||
</div>
|
||||
|
||||
{deployments?.map((deployment) => (
|
||||
@@ -88,7 +87,14 @@ const History = () => {
|
||||
className="flex flex-col sm:flex-row text-secondary-foreground border-b dark:border-stone-500 sm:p-2 hover:bg-muted/50 text-sm"
|
||||
>
|
||||
<div className="sm:w-48 w-full pt-1 sm:pt-0 flex items-center">
|
||||
{deployment.expand.domain?.domain}
|
||||
{deployment.expand.domain?.domain
|
||||
.split(";")
|
||||
.map((domain: string) => (
|
||||
<>
|
||||
{domain}
|
||||
<br />
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
<div className="sm:w-24 w-full pt-1 sm:pt-0 flex items-center">
|
||||
<DeployState deployment={deployment} />
|
||||
@@ -106,14 +112,14 @@ const History = () => {
|
||||
<Sheet>
|
||||
<SheetTrigger asChild>
|
||||
<Button variant={"link"} className="p-0">
|
||||
{t('deployment.log.detail.button.text')}
|
||||
{t("deployment.log.detail.button.text")}
|
||||
</Button>
|
||||
</SheetTrigger>
|
||||
<SheetContent className="sm:max-w-5xl">
|
||||
<SheetHeader>
|
||||
<SheetTitle>
|
||||
{deployment.expand.domain?.domain}-{deployment.id}
|
||||
{t('deployment.log.detail')}
|
||||
{t("deployment.log.detail")}
|
||||
</SheetTitle>
|
||||
</SheetHeader>
|
||||
<div className="bg-gray-950 text-stone-100 p-5 text-sm h-[80dvh]">
|
||||
|
||||
Reference in New Issue
Block a user