diff --git a/README.md b/README.md index 705682a9..d235ebf8 100644 --- a/README.md +++ b/README.md @@ -16,11 +16,6 @@ -> [!WARNING] -> 当前分支为 `next`,是 v0.3.x 的开发分支,目前还没有稳定,请勿在生产环境中使用。 -> -> 如需访问之前的版本,请切换至 `main` 分支。 - --- ## 🚩 项目简介 @@ -69,9 +64,9 @@ Certimate 旨在为用户提供一个安全、简便的 SSL 证书管理解决 如何使用 Docker 或其他部署方式请参考文档。 -## 📄 技术文档 +## 📄 使用手册 -请访问 [docs.certimate.me](https://docs.certimate.me/) 以阅读技术文档。 +请访问文档站 [docs.certimate.me](https://docs.certimate.me/) 以阅读使用手册。 相关文章: diff --git a/README_EN.md b/README_EN.md index b59284f6..0ef5cdaa 100644 --- a/README_EN.md +++ b/README_EN.md @@ -16,11 +16,6 @@ -> [!WARNING] -> The current branch is `next`, which is the development branch for v0.3.x. It is currently unstable and should not be used in production environments. -> -> To access the previous versions, please switch to the `main` branch. - --- ## 🚩 Introduction @@ -60,7 +55,7 @@ Download the archived package of precompiled binary files directly from [GitHub Visit `http://127.0.0.1:8090` in your browser. -Initial administrator account: +Default administrator account: - Username: `admin@certimate.fun` - Password: `1234567890` @@ -69,7 +64,7 @@ Work with Certimate right now. Or read other content in the documentation to lea ## 📄 Documentation -Please visit [docs.certimate.me](https://docs.certimate.me/en/). +Please visit the documentation site [docs.certimate.me](https://docs.certimate.me/en/). Related articles: diff --git a/go.mod b/go.mod index ecf902f8..123c69ae 100644 --- a/go.mod +++ b/go.mod @@ -6,71 +6,75 @@ toolchain go1.23.2 require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 - github.com/alibabacloud-go/alb-20200616/v2 v2.2.7 + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 + github.com/Azure/azure-sdk-for-go/sdk/keyvault/azcertificates v0.9.0 + github.com/G-Core/gcorelabscdn-go v1.0.26 + github.com/alibabacloud-go/alb-20200616/v2 v2.2.8 github.com/alibabacloud-go/cas-20200407/v3 v3.0.4 github.com/alibabacloud-go/cdn-20180510/v5 v5.2.2 - github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10 - github.com/alibabacloud-go/esa-20240910/v2 v2.13.0 + github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.2 + github.com/alibabacloud-go/esa-20240910/v2 v2.22.1 github.com/alibabacloud-go/live-20161101 v1.1.1 github.com/alibabacloud-go/nlb-20220430/v2 v2.0.3 github.com/alibabacloud-go/slb-20140515/v4 v4.0.10 - github.com/alibabacloud-go/tea v1.2.2 - github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.0.4 + github.com/alibabacloud-go/tea v1.3.2 + github.com/alibabacloud-go/vod-20170321/v4 v4.6.1 + github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.0.5 github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible - github.com/aws/aws-sdk-go-v2/service/acm v1.30.18 - github.com/aws/aws-sdk-go-v2/service/cloudfront v1.44.10 - github.com/baidubce/bce-sdk-go v0.9.217 + github.com/aws/aws-sdk-go-v2/service/acm v1.31.1 + github.com/aws/aws-sdk-go-v2/service/cloudfront v1.45.1 + github.com/baidubce/bce-sdk-go v0.9.218 github.com/byteplus-sdk/byteplus-sdk-golang v1.0.41 github.com/go-acme/lego/v4 v4.22.2 github.com/go-resty/resty/v2 v2.16.5 github.com/go-viper/mapstructure/v2 v2.2.1 - github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.136 + github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.138 + github.com/jdcloud-api/jdcloud-sdk-go v1.62.0 github.com/nikoksr/notify v1.3.0 github.com/pavlo-v-chernykh/keystore-go/v4 v4.5.0 github.com/pkg/sftp v1.13.7 github.com/pocketbase/dbx v1.11.0 - github.com/pocketbase/pocketbase v0.25.4 + github.com/pocketbase/pocketbase v0.25.9 github.com/povsister/scp v0.0.0-20240802064259-28781e87b246 github.com/qiniu/go-sdk/v7 v7.25.2 - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1096 - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1096 - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1102 - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1096 - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1096 - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1096 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1115 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1115 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1115 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1115 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1115 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1115 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.0.1102 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1099 github.com/ucloud/ucloud-sdk-go v0.22.31 github.com/volcengine/ve-tos-golang-sdk/v2 v2.7.9 - github.com/volcengine/volc-sdk-golang v1.0.195 - github.com/volcengine/volcengine-go-sdk v1.0.180 - golang.org/x/crypto v0.33.0 - golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac - k8s.io/api v0.32.1 - k8s.io/apimachinery v0.32.1 - k8s.io/client-go v0.32.1 + github.com/volcengine/volc-sdk-golang v1.0.197 + github.com/volcengine/volcengine-go-sdk v1.0.184 + gitlab.ecloud.com/ecloud/ecloudsdkclouddns v1.0.1 + gitlab.ecloud.com/ecloud/ecloudsdkcore v1.0.0 + golang.org/x/crypto v0.36.0 + golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 + k8s.io/api v0.32.2 + k8s.io/apimachinery v0.32.2 + k8s.io/client-go v0.32.2 software.sslmate.com/src/go-pkcs12 v0.5.0 ) require ( - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/keyvault/azcertificates v0.9.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.3.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates v1.3.1 // indirect - github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 // indirect - github.com/G-Core/gcorelabscdn-go v1.0.26 // indirect + github.com/alibabacloud-go/alibabacloud-gateway-fc-util v0.0.7 // indirect + github.com/alibabacloud-go/fc-20230330/v4 v4.1.7 // indirect + github.com/alibabacloud-go/fc-open-20210406 v1.1.14 // indirect + github.com/alibabacloud-go/fc-open-20210406/v2 v2.0.12 // indirect github.com/alibabacloud-go/openplatform-20191219/v2 v2.0.1 // indirect github.com/alibabacloud-go/tea-fileform v1.1.1 // indirect github.com/alibabacloud-go/tea-oss-sdk v1.1.3 // indirect github.com/alibabacloud-go/tea-oss-utils v1.1.0 // indirect - github.com/alibabacloud-go/tea-rpc v1.1.3 // indirect - github.com/alibabacloud-go/tea-rpc-utils v1.1.0 // indirect github.com/alibabacloud-go/tea-utils/v2 v2.0.7 // indirect - github.com/alibabacloud-go/vod-20170321 v1.0.1 // indirect - github.com/alibabacloud-go/vod-20170321/v4 v4.6.1 // indirect github.com/avast/retry-go v3.0.0+incompatible // indirect github.com/aws/aws-sdk-go-v2/service/route53 v1.48.1 // indirect github.com/blinkbean/dingtalk v1.1.3 // indirect @@ -92,7 +96,6 @@ require ( github.com/google/gnostic-models v0.6.9 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/jdcloud-api/jdcloud-sdk-go v1.62.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect @@ -106,11 +109,8 @@ require ( github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/technoweenie/multipartstreamer v1.0.1 // indirect - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.0.1102 // indirect - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1099 // indirect + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1115 // indirect github.com/x448/float16 v0.8.4 // indirect - gitlab.ecloud.com/ecloud/ecloudsdkclouddns v1.0.1 // indirect - gitlab.ecloud.com/ecloud/ecloudsdkcore v1.0.0 // indirect go.mongodb.org/mongo-driver v1.17.2 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect @@ -136,14 +136,14 @@ require ( github.com/aliyun/alibaba-cloud-sdk-go v1.63.83 // indirect github.com/aliyun/credentials-go v1.4.3 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect - github.com/aws/aws-sdk-go-v2 v1.36.1 + github.com/aws/aws-sdk-go-v2 v1.36.3 github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.8 // indirect github.com/aws/aws-sdk-go-v2/config v1.29.5 github.com/aws/aws-sdk-go-v2/credentials v1.17.58 github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.28 // indirect github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.58 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.32 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.32 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.32 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 // indirect @@ -170,7 +170,7 @@ require ( github.com/goccy/go-json v0.10.4 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/uuid v1.6.0 // indirect + github.com/google/uuid v1.6.0 github.com/googleapis/gax-go/v2 v2.14.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect @@ -196,15 +196,15 @@ require ( go.opencensus.io v0.24.0 // indirect gocloud.dev v0.40.0 // indirect golang.org/x/image v0.24.0 // indirect - golang.org/x/mod v0.23.0 // indirect - golang.org/x/net v0.35.0 // indirect + golang.org/x/mod v0.24.0 // indirect + golang.org/x/net v0.37.0 // indirect golang.org/x/oauth2 v0.26.0 // indirect - golang.org/x/sync v0.11.0 - golang.org/x/sys v0.30.0 // indirect - golang.org/x/term v0.29.0 // indirect - golang.org/x/text v0.22.0 // indirect + golang.org/x/sync v0.12.0 + golang.org/x/sys v0.31.0 // indirect + golang.org/x/term v0.30.0 // indirect + golang.org/x/text v0.23.0 // indirect golang.org/x/time v0.9.0 - golang.org/x/tools v0.30.0 // indirect + golang.org/x/tools v0.31.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect google.golang.org/api v0.220.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 // indirect @@ -212,10 +212,10 @@ require ( google.golang.org/protobuf v1.36.5 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - modernc.org/libc v1.61.11 // indirect + modernc.org/libc v1.61.13 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.8.2 // indirect - modernc.org/sqlite v1.34.5 // indirect + modernc.org/sqlite v1.35.0 // indirect ) replace gitlab.ecloud.com/ecloud/ecloudsdkcore v1.0.0 => ./internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0 diff --git a/go.sum b/go.sum index a9d2d038..04555b1e 100644 --- a/go.sum +++ b/go.sum @@ -52,13 +52,10 @@ filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4 github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 h1:g0EZJwz7xkXQiZAI5xi9f3WWFYBlX1CPTrR+NDToRkQ= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0/go.mod h1:XCW7KnZet0Opnr7HccfUw1PLc4CjHqpcaxW8DHklNkQ= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.1 h1:1mvYtZfWQAnwNah/C+Z+Jb9rQH95LPE2vlmMuWAHJk8= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.1/go.mod h1:75I/mXtme1JyWFtz8GocPHVFyH421IBoZErnO16dd0k= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 h1:F0gBpfdPLGsw+nsgk6aqqkZS1jiixa5WwFe3fk/T3Ys= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2/go.mod h1:SqINnQ9lVVdRlyC8cd1lCI0SdX4n2paeABd2K8ggfnE= -github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.1 h1:Bk5uOhSAenHyR5P61D/NzeQCv+4fEVV8mOkJ82NqpWw= -github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.1/go.mod h1:QZ4pw3or1WPmRBxf0cHd1tknzrT54WPBOQoGutCPvSU= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= github.com/Azure/azure-sdk-for-go/sdk/keyvault/azcertificates v0.9.0 h1:btEsytNrA4TG3edZnnUnzOz8W2MjOd6Bu3/7xyOXSOY= @@ -75,14 +72,8 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourceg github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.0/go.mod h1:wVEOJfGTj0oPAUGA1JuRAvz/lxXQsWW16axmHPP47Bk= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0 h1:Dd+RhdJn0OTtVGaeDLZpcumkIVCtA/3/Fo42+eoYvVM= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0/go.mod h1:5kakwfW5CjC9KK+Q4wjXAg+ShuIm2mBMua0ZFj2C8PE= -github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates v1.3.1 h1:HUJQzFYTv7t3V1dxPms52eEgl0l9xCNqutDrY45Lvmw= -github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates v1.3.1/go.mod h1:ig/8nSkzmfxm5QGeIy5JYIEj8JEFy5JxvY3OB1YNRC4= -github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1 h1:bFWuoEKg+gImo7pvkiQEFAc8ocibADgXeiLAxWhWmkI= -github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1/go.mod h1:Vih/3yc6yac2JzU4hzpaDupBJP0Flaia9rXXrU8xyww= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= -github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2 h1:kYRSnvJju5gYVyhkij+RTJ/VR6QIUaCfWeaFm2ycsjQ= -github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 h1:H5xDQaE3XowWfhZRUpnfC+rGZMEVoSiji+b+/HFAPU4= github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -117,8 +108,11 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alex-ant/gomath v0.0.0-20160516115720-89013a210a82/go.mod h1:nLnM0KdK1CmygvjpDUO6m1TjSsiQtL61juhNsvV/JVI= -github.com/alibabacloud-go/alb-20200616/v2 v2.2.7 h1:IdNb5qq+/j2WdpCLOYphZD7ETkmxuPEZLs9qFmrXlEY= -github.com/alibabacloud-go/alb-20200616/v2 v2.2.7/go.mod h1:jU/K+GVb5b0vjiDpkf6E0dH77tsi1jTLGWm4ouCiRxk= +github.com/alibabacloud-go/alb-20200616/v2 v2.2.8 h1:/6+1AqIiENG3u6RmEYWEQ/YZv3YgdFZkE6Xd9RZM6n0= +github.com/alibabacloud-go/alb-20200616/v2 v2.2.8/go.mod h1:jU/K+GVb5b0vjiDpkf6E0dH77tsi1jTLGWm4ouCiRxk= +github.com/alibabacloud-go/alibabacloud-gateway-fc-util v0.0.6/go.mod h1:H0RPHXHP/ICfEQrKzQcCqXI15jcV4zaDPCOAmh3U9O8= +github.com/alibabacloud-go/alibabacloud-gateway-fc-util v0.0.7 h1:RDatRb9RG39HjkevgzTeiVoDDaamoB+12GHNairp3Ag= +github.com/alibabacloud-go/alibabacloud-gateway-fc-util v0.0.7/go.mod h1:H0RPHXHP/ICfEQrKzQcCqXI15jcV4zaDPCOAmh3U9O8= github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6 h1:eIf+iGJxdU4U9ypaUfbtOWCsZSbTb8AUHvyPrxu6mAA= github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6/go.mod h1:4EUIoxs/do24zMOGGqYVWgw0s9NtiylnJglOeEB5UJo= github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc= @@ -135,10 +129,12 @@ github.com/alibabacloud-go/darabonba-encode-util v0.0.2/go.mod h1:JiW9higWHYXm7F github.com/alibabacloud-go/darabonba-map v0.0.2 h1:qvPnGB4+dJbJIxOOfawxzF3hzMnIpjmafa0qOTp6udc= github.com/alibabacloud-go/darabonba-map v0.0.2/go.mod h1:28AJaX8FOE/ym8OUFWga+MtEzBunJwQGceGQlvaPGPc= github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.0/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ= +github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.1/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ= github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.2/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ= github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.5/go.mod h1:kUe8JqFmoVU7lfBauaDD5taFaW7mBI+xVsyHutYtabg= -github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10 h1:GEYkMApgpKEVDn6z12DcH1EGYpDYRB8JxsazM4Rywak= github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10/go.mod h1:26a14FGhZVELuz2cc2AolvW4RHmIO3/HRwsdHhaIPDE= +github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.2 h1:/tEcF4JeJLi3Mtq66ZFm/EYu4jRixJZtOhBkrU1mfBw= +github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.2/go.mod h1:Wxis0IBFusdbo44HO6KYYCJR1rRkoh47QQOYWvaheSU= github.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg= github.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ= github.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo= @@ -152,8 +148,14 @@ github.com/alibabacloud-go/debug v1.0.1/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/ql github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE= github.com/alibabacloud-go/endpoint-util v1.1.1 h1:ZkBv2/jnghxtU0p+upSU0GGzW1VL9GQdZO3mcSUTUy8= github.com/alibabacloud-go/endpoint-util v1.1.1/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE= -github.com/alibabacloud-go/esa-20240910/v2 v2.13.0 h1:qLYLwczIIzoB1XxkyNC7rxbL3wkyBmVTAJZ+WZPtBTM= -github.com/alibabacloud-go/esa-20240910/v2 v2.13.0/go.mod h1:P1w/+i7dE2xSXVHJznEOVImlLtqqrzUJQQk2AsyBJ6o= +github.com/alibabacloud-go/esa-20240910/v2 v2.22.1 h1:Wmvb90nS6IxJjVe+fUWv7jtXFrJttSh/WkFQ2HIsQmQ= +github.com/alibabacloud-go/esa-20240910/v2 v2.22.1/go.mod h1:P1w/+i7dE2xSXVHJznEOVImlLtqqrzUJQQk2AsyBJ6o= +github.com/alibabacloud-go/fc-20230330/v4 v4.1.7 h1:rQvPfzPaouL/WGNgMDMCplA4wDscmVFff7aLCUkjv4g= +github.com/alibabacloud-go/fc-20230330/v4 v4.1.7/go.mod h1:ssEfKO6MskPtq7QaQnyiOHGWLXOZcl7a8YIf8u56DGc= +github.com/alibabacloud-go/fc-open-20210406 v1.1.14 h1:avhpcxvdwexER2S1buxgnYoEq+/rWX3iMCgP3EZZz+E= +github.com/alibabacloud-go/fc-open-20210406 v1.1.14/go.mod h1:M3vmom/tsiVbnIBBZshm8JBXcniX9Ryek3NFX2Q95dg= +github.com/alibabacloud-go/fc-open-20210406/v2 v2.0.12 h1:A3D8Mp6qf8DfR6Dt5MpS8aDVaWfS4N85T5CvGUvgrjM= +github.com/alibabacloud-go/fc-open-20210406/v2 v2.0.12/go.mod h1:F5c0E5UB3k8v6neTtw3FBcJ1YCNFzVoL1JPRHTe33u4= github.com/alibabacloud-go/live-20161101 v1.1.1 h1:rUGfA8RHmCMtQ5M3yMSyRde+yRXWqVecmiXBU3XrGJ8= github.com/alibabacloud-go/live-20161101 v1.1.1/go.mod h1:g84w6qeAodT0/IHdc0tEed2a8PyhQhYl7TAj3jGl4A4= github.com/alibabacloud-go/nlb-20220430/v2 v2.0.3 h1:LtyUVlgBEKyzWgQJurzXM6MXCt84sQr9cE5OKqYymko= @@ -176,19 +178,15 @@ github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy github.com/alibabacloud-go/tea v1.1.19/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= github.com/alibabacloud-go/tea v1.2.1/go.mod h1:qbzof29bM/IFhLMtJPrgTGK3eauV5J2wSyEUo4OEmnA= -github.com/alibabacloud-go/tea v1.2.2 h1:aTsR6Rl3ANWPfqeQugPglfurloyBJY85eFy7Gc1+8oU= github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk= +github.com/alibabacloud-go/tea v1.3.2 h1:4xlOnwYaK3ek1Kh+fgYTOYYOfv+uv3SAiJEIYm+8vJk= +github.com/alibabacloud-go/tea v1.3.2/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg= github.com/alibabacloud-go/tea-fileform v1.1.1 h1:1YG6erAP3joQ0XdCXYIotuD7zyOM6qCR49xkp5FZDeU= github.com/alibabacloud-go/tea-fileform v1.1.1/go.mod h1:ZeCV91o4ISmxidd686f0ebdS5EDHWU+vW+TkjLhrsFE= github.com/alibabacloud-go/tea-oss-sdk v1.1.3 h1:EhAHI6edMeqgkZEqP7r4nc9iMWAUBKGxJHoBsOSKTtU= github.com/alibabacloud-go/tea-oss-sdk v1.1.3/go.mod h1:yUnodpR3Bf2rudLE7V/Gft5txjJF30Pk+hH77K/Eab0= github.com/alibabacloud-go/tea-oss-utils v1.1.0 h1:y65crjjcZ2Pbb6UZtC2deuIZHDVTS3IaDWE7M9nVLRc= github.com/alibabacloud-go/tea-oss-utils v1.1.0/go.mod h1:PFCF12e9yEKyBUIn7X1IrF/pNjvxgkHy0CgxX4+xRuY= -github.com/alibabacloud-go/tea-rpc v1.1.3 h1:uuxAIT9PB6MMABQfV/EMSnREZjh629WXu+hmPNF1IAs= -github.com/alibabacloud-go/tea-rpc v1.1.3/go.mod h1:uwhvnxPK69jcAYkVyP1WCFhTh1oVLiibUseSUpC7L8g= -github.com/alibabacloud-go/tea-rpc-utils v1.1.0 h1:kIG7+9sMRaDzvCbXfowycEwFRdnLAglRFQ/dnc0/JNE= -github.com/alibabacloud-go/tea-rpc-utils v1.1.0/go.mod h1:rxGY+fLbm3Fj3oJpeU0hBTmz52Ux50nm7JL01tyPv9c= -github.com/alibabacloud-go/tea-utils v1.3.0/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE= github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE= github.com/alibabacloud-go/tea-utils v1.3.6/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE= github.com/alibabacloud-go/tea-utils v1.4.5 h1:h0/6Xd2f3bPE4XHTvkpjwxowIwRCJAJOqY6Eq8f3zfA= @@ -204,17 +202,14 @@ 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/alibabacloud-go/vod-20170321 v1.0.1 h1:ZiBggVoJegu0Q3iarHZyveTOJJE0kUym6RCSLM9epoc= -github.com/alibabacloud-go/vod-20170321 v1.0.1/go.mod h1:eKaYMCAd22pgBFMz0Ci/o2l+UJSrq24LLSF/XyaTiac= github.com/alibabacloud-go/vod-20170321/v4 v4.6.1 h1:6JTNq23lMo3wOui5qjpUJu2VKBgSHR4ArMgbKDOej7Q= github.com/alibabacloud-go/vod-20170321/v4 v4.6.1/go.mod h1:TkgLKMSLu0qZN8Qdcu8svfHREyI64kjFvrp/GhrD4VQ= -github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.0.4 h1:Od0KgA73DyG9X2XFwuZZTkDv2pzA6B5mhYapyyca6QE= -github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.0.4/go.mod h1:DohGoS8BnMxHXghHebtjPP7+GMdxPsRN19T3nn2HcCU= +github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.0.5 h1:ldAm1nvsCq66igjtcZyGhAoLClr+2eZ/pMIBUdKCOMM= +github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.0.5/go.mod h1:DohGoS8BnMxHXghHebtjPP7+GMdxPsRN19T3nn2HcCU= github.com/aliyun/alibaba-cloud-sdk-go v1.63.83 h1:YBkf7H5CSgrlb3C1aWcpDt7Vk8UEGFPeD2OOirtt6IM= github.com/aliyun/alibaba-cloud-sdk-go v1.63.83/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ= github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g= github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= -github.com/aliyun/credentials-go v1.1.0/go.mod h1:ZXrrxv386Mj6z8NpihLKpexQE550m7j3LlyCvYub9aE= github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw= github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0= github.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM= @@ -236,8 +231,8 @@ github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= -github.com/aws/aws-sdk-go-v2 v1.36.1 h1:iTDl5U6oAhkNPba0e1t1hrwAo02ZMqbrGq4k5JBWM5E= -github.com/aws/aws-sdk-go-v2 v1.36.1/go.mod h1:5PMILGVKiW32oDzjj6RU52yrNrDPUHcbZQYr1sM7qmM= +github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM= +github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.8 h1:zAxi9p3wsZMIaVCdoiQp2uZ9k1LsZvmAnoTBeZPXom0= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.8/go.mod h1:3XkePX5dSaxveLAYY7nsbsZZrKxCyEuE5pM4ziFxyGg= github.com/aws/aws-sdk-go-v2/config v1.29.5 h1:4lS2IB+wwkj5J43Tq/AwvnscBerBJtQQ6YS7puzCI1k= @@ -248,18 +243,18 @@ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.28 h1:KwsodFKVQTlI5EyhRSugAL github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.28/go.mod h1:EY3APf9MzygVhKuPXAc5H+MkGb8k/DOSQjWS0LgkKqI= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.58 h1:/BsEGAyMai+KdXS+CMHlLhB5miAO19wOqE6tj8azWPM= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.58/go.mod h1:KHM3lfl/sAJBCoLI1Lsg5w4SD2VDYWwQi7vxbKhw7TI= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.32 h1:BjUcr3X3K0wZPGFg2bxOWW3VPN8rkE3/61zhP+IHviA= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.32/go.mod h1:80+OGC/bgzzFFTUmcuwD0lb4YutwQeKLFpmt6hoWapU= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.32 h1:m1GeXHVMJsRsUAqG6HjZWx9dj7F5TR+cF1bjyfYyBd4= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.32/go.mod h1:IitoQxGfaKdVLNg0hD8/DXmAqNy0H4K2H2Sf91ti8sI= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34/go.mod h1:p4VfIceZokChbA9FzMbRGz5OV+lekcVtHlPKEO0gSZY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0ioo/gq8Mn6u9w19Mri8DnJ15Jf0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 h1:Pg9URiobXy85kgFev3og2CuOZ8JZUBENF+dcgWBaYNk= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.32 h1:OIHj/nAhVzIXGzbAE+4XmZ8FPvro3THr6NlqErJc3wY= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.32/go.mod h1:LiBEsDo34OJXqdDlRGsilhlIiXR7DL+6Cx2f4p1EgzI= -github.com/aws/aws-sdk-go-v2/service/acm v1.30.18 h1:/MZpjVk95P+lF9dUcOmyQwp1r0Ld4A8AxfQLdf1w8bU= -github.com/aws/aws-sdk-go-v2/service/acm v1.30.18/go.mod h1:JaIJpS5R/ADAyK2gGYcQSmpMyty24/nLxvwsPe629BI= -github.com/aws/aws-sdk-go-v2/service/cloudfront v1.44.10 h1:fdLh7eMf5mxtggx2nG0+cFkaiRK+ULCOPK3qq8eTje4= -github.com/aws/aws-sdk-go-v2/service/cloudfront v1.44.10/go.mod h1:uBca+/1aH5v/RYWXqyymLrsbmx1vU9bBxeurlC627Gc= +github.com/aws/aws-sdk-go-v2/service/acm v1.31.1 h1:FB1PgU6vlXbqehxZiHuYQRWo5Ou6sQrFJcUaRe27lRo= +github.com/aws/aws-sdk-go-v2/service/acm v1.31.1/go.mod h1:3sKYAgRbuBa2QMYGh/WEclwnmfx+QoPhhX25PdSQSQM= +github.com/aws/aws-sdk-go-v2/service/cloudfront v1.45.1 h1:i5znMqubyVRwPT8MsBndfhtvjuSj4qRVAh9oVRXRPcI= +github.com/aws/aws-sdk-go-v2/service/cloudfront v1.45.1/go.mod h1:FIBJ48TS+qJb+Ne4qJ+0NeIhtPTVXItXooTeNeVI4Po= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 h1:D4oz8/CzT9bAEYtVhSBmFj2dNOtaHOtMKc2vHBwYizA= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2/go.mod h1:Za3IHqTQ+yNcRHxu1OFucBh0ACZT4j4VQFF0BqpZcLY= @@ -282,10 +277,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.33.14/go.mod h1:dspXf/oYWGWo6DEvj98w github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ= github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= -github.com/baidubce/bce-sdk-go v0.9.216 h1:jRq4C1UGYcvHo6Gst2kuUzhWwJM6EqXCmhIsTKQvf4k= -github.com/baidubce/bce-sdk-go v0.9.216/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg= -github.com/baidubce/bce-sdk-go v0.9.217 h1:dbMeVzpr9BGItTFHB1s2KSrpz0ayJC1y366VUMmaF0k= -github.com/baidubce/bce-sdk-go v0.9.217/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg= +github.com/baidubce/bce-sdk-go v0.9.218 h1:yOoktcJOoyCJmq06m6nZAif+RMndT4fF+Zj9RfidEn0= +github.com/baidubce/bce-sdk-go v0.9.218/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -387,8 +380,6 @@ github.com/gammazero/toposort v0.1.1/go.mod h1:H2cozTnNpMw0hg2VHAYsAxmkHXBYroNan github.com/ganigeorgiev/fexpr v0.4.1 h1:hpUgbUEEWIZhSDBtf4M9aUNfQQ0BZkGRaMePy7Gcx5k= github.com/ganigeorgiev/fexpr v0.4.1/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO2WtJkF5drE= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-acme/lego/v4 v4.21.0 h1:arEW+8o5p7VI8Bk1kr/PDlgD1DrxtTH1gJ4b7mehL8o= -github.com/go-acme/lego/v4 v4.21.0/go.mod h1:HrSWzm3Ckj45Ie3i+p1zKVobbQoMOaGu9m4up0dUeDI= github.com/go-acme/lego/v4 v4.22.2 h1:ck+HllWrV/rZGeYohsKQ5iKNnU/WAZxwOdiu6cxky+0= github.com/go-acme/lego/v4 v4.22.2/go.mod h1:E2FndyI3Ekv0usNJt46mFb9LVpV/XBYT+4E3tz02Tzo= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -587,10 +578,8 @@ github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.135 h1:UbNMlPfh0GhRY3iVkvv4fXFJ+bLqXoVCwjqe6geFdPs= -github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.135/go.mod h1:Y/+YLCFCJtS29i2MbYPTUlNNfwXvkzEsZKR0imY/2aY= -github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.136 h1:T785NUg5245nWpPVHLVR8lBd+zGQYR14Vi/TCX1iu3A= -github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.136/go.mod h1:Y/+YLCFCJtS29i2MbYPTUlNNfwXvkzEsZKR0imY/2aY= +github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.138 h1:VH/OZE73y0IRomF9QqCw71etSdfFbQIq/utq164IOVg= +github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.138/go.mod h1:Y/+YLCFCJtS29i2MbYPTUlNNfwXvkzEsZKR0imY/2aY= github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo= github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -761,8 +750,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pocketbase/dbx v1.11.0 h1:LpZezioMfT3K4tLrqA55wWFw1EtH1pM4tzSVa7kgszU= github.com/pocketbase/dbx v1.11.0/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWKhu2vhMs= -github.com/pocketbase/pocketbase v0.25.4 h1:3bsq+9RvLUmQs6bRlhuO0UiUnf9tt6aODPTHQlj8pYk= -github.com/pocketbase/pocketbase v0.25.4/go.mod h1:CfcfWJ2u4eWaQbrpZ1rEkqIk9rB521yb9JVLNpEl/8E= +github.com/pocketbase/pocketbase v0.25.9 h1:/PSJcy39vEGv4lsBG4HV0ZFLcFsTdK9oMkJbxVlVJSs= +github.com/pocketbase/pocketbase v0.25.9/go.mod h1:gOnPr+g/GS+iqKh5XYXycdRWVGhiHY4c1H4TGjU9DDw= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/povsister/scp v0.0.0-20240802064259-28781e87b246 h1:c4D8BPWLOxxdaxQLfLKQXH2YXY/E9yo3jrDSL54XrTw= @@ -855,25 +844,25 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf github.com/stretchr/testify v1.10.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/cdn v1.0.1096 h1:/nbiqUXO5/7WYATAGt65ULSEB48q+gCws6rI8kkt8Ck= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1096/go.mod h1:EtQl1Sj7WaofRoyetOsDqCO+MvnFMba3ZUrD9KZo5sQ= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1096 h1:Z9I0iPNWfwbwRcPrWaY5w5WL2d6NrlyBI1dSGq7jobk= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1096/go.mod h1:lQBepDW2LTraTn+zOwgtoU1zVmKvgsUWqMjtmTRjn30= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1115 h1:HsrXyqKQB2mKfGq+ZkbylRCMrbtPCmmUBrwA8MhhEX0= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1115/go.mod h1:5cz1DtLlXK98U1Hh36oW4PjVOU+mbKg5wtCDmCc9Fcs= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1115 h1:QClUB1NRQNQSn4yp2msXjuU6aHS+5YKlAOL4tdrGtcs= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1115/go.mod h1:4MCC7p86SOARKb0P6FGC9s6KvCETI6t4oFrXDjgZD0M= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1084/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1096 h1:DMokC7T0UF8wMfT1kD+mX3M+hc2C06gmFvQ9gsfRPmI= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1096/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1099 h1:4fQ53ORk6Eayw1H2kg43PoBnUuhGR6WRG6rtec/i3oI= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1099/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1102 h1:DxsNhw67OHyQME20IULmi8lgNY9MHuQ+qS1XH1/yTvM= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1102/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1115 h1:lYeFC379r76seyzN7PHmSxv1ji9knmsXQJglDB/K0WE= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1115/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1084 h1:kwctN0WQYt8/iKP+iRCTCwdzEMIXsXklbRIib5rjeQ8= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1084/go.mod h1:qE67ApiBzeRvzeDsV+GxyIDbVIDemsKpHXllQATz/Vw= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1096 h1:h9FP40Ycg45egJlZcjbLyc4IUeFoq+wSpR43sHMALtM= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1096/go.mod h1:+Np3rsf08RDXsl8+7/MC4QcUeOuZj0KwNhA8tkL7BXg= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1096 h1:7ZmPusU52i5bT9bf5xBeqJclyBx75zFGEIOmiXme9YU= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1096/go.mod h1:aMpGcDskqqhXtfMaeo2egO61tgh/zt07L1ohSPwmjWk= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1096 h1:N62IFKL1ZRNQ7WPLNn8x9eYnwM4lOUIVY3buW6kbGtg= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1096/go.mod h1:4PZRRpZp+jvYBUbUajsoZREnk7sJXMnPAiGB4IX8IkM= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1115 h1:qy05kto0yI5AG6u0+BHwfUK9jJUJ92081ee+wvSkpk8= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1115/go.mod h1:BSeUvwz3WO7BbTan1OKC0+NDeiULVZVovrd93qCtWJM= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1115 h1:Qi7VWmJ0AQxEMlwKpbWfnsLA5QdNxekdcLJTBVdO85U= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1115/go.mod h1:P16nIMvmpSY+arTc2m2HyJmrYQP6CFnr48glz0+abyw= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1115 h1:xAMIp4en0Wm4FAS4zo5ZXeYT4FMXms68Fc2COP4J/TM= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1115/go.mod h1:3zCzHke2XQMBm6T2PIdnfTCXGxykV4uTTdRStpUdS0g= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1115 h1:3Xz/q/m9gl++KtPkrgaXvFCXjM1y9QmAbpG8qfLUm9M= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1115/go.mod h1:/NqwqdSTa8u2xPmr9BpAzY+2c49NP23AEGpkN93AR6g= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.0.1102 h1:B0mJk0ojVOFCMLrBoxLNVgrGih11EezTekRffkACCAY= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.0.1102/go.mod h1:0yyQ1r35jteb5DV4mcJZ5uh9NStWzjMYz9iSMnDMdJA= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1099 h1:kD+8RKF0uJCr7VaurAUA11NNAoln0HaagMCgQV6EnUw= @@ -892,12 +881,10 @@ github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/X github.com/volcengine/ve-tos-golang-sdk/v2 v2.7.9 h1:fEnScn2dXfvfNcFnvJnpf/cYdj8kLIe5QC5qORlFO2c= github.com/volcengine/ve-tos-golang-sdk/v2 v2.7.9/go.mod h1:IrjK84IJJTuOZOTMv/P18Ydjy/x+ow7fF7q11jAxXLM= github.com/volcengine/volc-sdk-golang v1.0.23/go.mod h1:AfG/PZRUkHJ9inETvbjNifTDgut25Wbkm2QoYBTbvyU= -github.com/volcengine/volc-sdk-golang v1.0.194 h1:3o0INQzdtYJWvdGrtX02booCqPL5TsWSq2W1Ur7Bzlo= -github.com/volcengine/volc-sdk-golang v1.0.194/go.mod h1:u0VtPvlXWpXDTmc9IHkaW1q+5Jjwus4oAqRhNMDRInE= -github.com/volcengine/volc-sdk-golang v1.0.195 h1:hKX4pBhmKcB3652BTdcAmtgizEPBnoQUpTM+j5blMA4= -github.com/volcengine/volc-sdk-golang v1.0.195/go.mod h1:stZX+EPgv1vF4nZwOlEe8iGcriUPRBKX8zA19gXycOQ= -github.com/volcengine/volcengine-go-sdk v1.0.180 h1:lzcNlaxeGIUdXgDuVH7KJwZYZjIZzaCAYPDh91htU6U= -github.com/volcengine/volcengine-go-sdk v1.0.180/go.mod h1:gfEDc1s7SYaGoY+WH2dRrS3qiuDJMkwqyfXWCa7+7oA= +github.com/volcengine/volc-sdk-golang v1.0.197 h1:jJlcMp+4i3lVL2ZZTVo8u3cndlXzC5SZoqH/4M6pyuw= +github.com/volcengine/volc-sdk-golang v1.0.197/go.mod h1:stZX+EPgv1vF4nZwOlEe8iGcriUPRBKX8zA19gXycOQ= +github.com/volcengine/volcengine-go-sdk v1.0.184 h1:bL8/dEkYwZvy5fqHO9+HIp1X6eBjIqR7yLmo+bmOaeU= +github.com/volcengine/volcengine-go-sdk v1.0.184/go.mod h1:gfEDc1s7SYaGoY+WH2dRrS3qiuDJMkwqyfXWCa7+7oA= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= @@ -979,13 +966,16 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= -golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= 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= @@ -999,8 +989,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac h1:l5+whBCLH3iH2ZNHYLbAe58bo7yrN4mVcnkHDYz5vvs= -golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac/go.mod h1:hH+7mtFmImwwcMvScyxUhjuVHR3HGaDPMn9rMSUUbxo= +golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw= +golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -1029,8 +1019,11 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 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.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= +golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= 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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1079,12 +1072,15 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 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.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= 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.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= +golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1106,8 +1102,11 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1176,26 +1175,33 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.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.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.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.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= 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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= -golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= -golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= +golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= +golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1211,8 +1217,10 @@ golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.11.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.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1272,8 +1280,10 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 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.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU= +golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ= 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= @@ -1425,12 +1435,12 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.32.1 h1:f562zw9cy+GvXzXf0CKlVQ7yHJVYzLfL6JAS4kOAaOc= -k8s.io/api v0.32.1/go.mod h1:/Yi/BqkuueW1BgpoePYBRdDYfjPF5sgTr5+YqDZra5k= -k8s.io/apimachinery v0.32.1 h1:683ENpaCBjma4CYqsmZyhEzrGz6cjn1MY/X2jB2hkZs= -k8s.io/apimachinery v0.32.1/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= -k8s.io/client-go v0.32.1 h1:otM0AxdhdBIaQh7l1Q0jQpmo7WOFIk5FFa4bg6YMdUU= -k8s.io/client-go v0.32.1/go.mod h1:aTTKZY7MdxUaJ/KiUs8D+GssR9zJZi77ZqtzcGXIiDg= +k8s.io/api v0.32.2 h1:bZrMLEkgizC24G9eViHGOPbW+aRo9duEISRIJKfdJuw= +k8s.io/api v0.32.2/go.mod h1:hKlhk4x1sJyYnHENsrdCWw31FEmCijNGPJO5WzHiJ6Y= +k8s.io/apimachinery v0.32.2 h1:yoQBR9ZGkA6Rgmhbp/yuT9/g+4lxtsGYwW6dR6BDPLQ= +k8s.io/apimachinery v0.32.2/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= +k8s.io/client-go v0.32.2 h1:4dYCD4Nz+9RApM2b/3BtVvBHw54QjMFUl1OLcJG5yOA= +k8s.io/client-go v0.32.2/go.mod h1:fpZ4oJXclZ3r2nDOv+Ux3XcJutfrwjKTCHz2H3sww94= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 h1:hcha5B1kVACrLujCKLbr8XWMxCxzQx42DY8QKYJrDLg= @@ -1439,15 +1449,15 @@ k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJ k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= modernc.org/cc/v4 v4.24.4 h1:TFkx1s6dCkQpd6dKurBNmpo+G8Zl4Sq/ztJ+2+DEsh0= modernc.org/cc/v4 v4.24.4/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= -modernc.org/ccgo/v4 v4.23.15 h1:wFDan71KnYqeHz4eF63vmGE6Q6Pc0PUGDpP0PRMYjDc= -modernc.org/ccgo/v4 v4.23.15/go.mod h1:nJX30dks/IWuBOnVa7VRii9Me4/9TZ1SC9GNtmARTy0= +modernc.org/ccgo/v4 v4.23.16 h1:Z2N+kk38b7SfySC1ZkpGLN2vthNJP1+ZzGZIlH7uBxo= +modernc.org/ccgo/v4 v4.23.16/go.mod h1:nNma8goMTY7aQZQNTyN9AIoJfxav4nvTnvKThAeMDdo= modernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8= modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= -modernc.org/gc/v2 v2.6.2 h1:YBXi5Kqp6aCK3fIxwKQ3/fErvawVKwjOLItxj1brGds= -modernc.org/gc/v2 v2.6.2/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= -modernc.org/libc v1.61.11 h1:6sZG8uB6EMMG7iTLPTndi8jyTdgAQNIeLGjCFICACZw= -modernc.org/libc v1.61.11/go.mod h1:HHX+srFdn839oaJRd0W8hBM3eg+mieyZCAjWwB08/nM= +modernc.org/gc/v2 v2.6.3 h1:aJVhcqAte49LF+mGveZ5KPlsp4tdGdAOT4sipJXADjw= +modernc.org/gc/v2 v2.6.3/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= +modernc.org/libc v1.61.13 h1:3LRd6ZO1ezsFiX1y+bHd1ipyEHIJKvuprv0sLTBwLW8= +modernc.org/libc v1.61.13/go.mod h1:8F/uJWL/3nNil0Lgt1Dpz+GgkApWh04N3el3hxJcA6E= modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= modernc.org/memory v1.8.2 h1:cL9L4bcoAObu4NkxOlKWBWtNHIsnnACGF/TbqQ6sbcI= @@ -1456,8 +1466,8 @@ modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= -modernc.org/sqlite v1.34.5 h1:Bb6SR13/fjp15jt70CL4f18JIN7p7dnMExd+UFnF15g= -modernc.org/sqlite v1.34.5/go.mod h1:YLuNmX9NKs8wRNK2ko1LW1NGYcc9FkBO69JOt1AR9JE= +modernc.org/sqlite v1.35.0 h1:yQps4fegMnZFdphtzlfQTCNBWtS0CZv48pRpW3RFHRw= +modernc.org/sqlite v1.35.0/go.mod h1:9cr2sicr7jIaWTBKQmAxQLfBv9LL0su4ZTEV+utt3ic= modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= diff --git a/internal/deployer/providers.go b/internal/deployer/providers.go index 6a8a0b6c..1efd9c96 100644 --- a/internal/deployer/providers.go +++ b/internal/deployer/providers.go @@ -6,12 +6,15 @@ import ( "github.com/usual2970/certimate/internal/domain" "github.com/usual2970/certimate/internal/pkg/core/deployer" + p1PanelConsole "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/1panel-console" + p1PanelSite "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/1panel-site" pAliyunALB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-alb" pAliyunCASDeploy "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-cas-deploy" pAliyunCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-cdn" pAliyunCLB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-clb" pAliyunDCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-dcdn" pAliyunESA "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-esa" + pAliyunFC "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-fc" pAliyunLive "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-live" pAliyunNLB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-nlb" pAliyunOSS "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-oss" @@ -47,6 +50,7 @@ import ( pTencentCloudCSS "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-css" pTencentCloudECDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-ecdn" pTencentCloudEO "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-eo" + pTencentCloudSCF "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-scf" pTencentCloudSSLDeploy "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-ssl-deploy" pTencentCloudVOD "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-vod" pTencentCloudWAF "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-waf" @@ -69,7 +73,38 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { NOTICE: If you add new constant, please keep ASCII order. */ switch options.Provider { - case domain.DeployProviderTypeAliyunALB, domain.DeployProviderTypeAliyunCASDeploy, domain.DeployProviderTypeAliyunCDN, domain.DeployProviderTypeAliyunCLB, domain.DeployProviderTypeAliyunDCDN, domain.DeployProviderTypeAliyunESA, domain.DeployProviderTypeAliyunLive, domain.DeployProviderTypeAliyunNLB, domain.DeployProviderTypeAliyunOSS, domain.DeployProviderTypeAliyunVOD, domain.DeployProviderTypeAliyunWAF: + case domain.DeployProviderType1PanelConsole, domain.DeployProviderType1PanelSite: + { + access := domain.AccessConfigFor1Panel{} + if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + switch options.Provider { + case domain.DeployProviderType1PanelConsole: + deployer, err := p1PanelConsole.NewDeployer(&p1PanelConsole.DeployerConfig{ + ApiUrl: access.ApiUrl, + ApiKey: access.ApiKey, + AllowInsecureConnections: access.AllowInsecureConnections, + AutoRestart: maps.GetValueAsBool(options.ProviderDeployConfig, "autoRestart"), + }) + return deployer, err + + case domain.DeployProviderType1PanelSite: + deployer, err := p1PanelSite.NewDeployer(&p1PanelSite.DeployerConfig{ + ApiUrl: access.ApiUrl, + ApiKey: access.ApiKey, + AllowInsecureConnections: access.AllowInsecureConnections, + WebsiteId: maps.GetValueAsInt64(options.ProviderDeployConfig, "websiteId"), + }) + return deployer, err + + default: + break + } + } + + case domain.DeployProviderTypeAliyunALB, domain.DeployProviderTypeAliyunCASDeploy, domain.DeployProviderTypeAliyunCDN, domain.DeployProviderTypeAliyunCLB, domain.DeployProviderTypeAliyunDCDN, domain.DeployProviderTypeAliyunESA, domain.DeployProviderTypeAliyunFC, domain.DeployProviderTypeAliyunLive, domain.DeployProviderTypeAliyunNLB, domain.DeployProviderTypeAliyunOSS, domain.DeployProviderTypeAliyunVOD, domain.DeployProviderTypeAliyunWAF: { access := domain.AccessConfigForAliyun{} if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { @@ -136,6 +171,16 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { }) return deployer, err + case domain.DeployProviderTypeAliyunFC: + deployer, err := pAliyunFC.NewDeployer(&pAliyunFC.DeployerConfig{ + AccessKeyId: access.AccessKeyId, + AccessKeySecret: access.AccessKeySecret, + Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), + ServiceVersion: maps.GetValueAsString(options.ProviderDeployConfig, "serviceVersion"), + Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + }) + return deployer, err + case domain.DeployProviderTypeAliyunLive: deployer, err := pAliyunLive.NewDeployer(&pAliyunLive.DeployerConfig{ AccessKeyId: access.AccessKeyId, @@ -262,19 +307,21 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { switch options.Provider { case domain.DeployProviderTypeBaotaPanelConsole: deployer, err := pBaotaPanelConsole.NewDeployer(&pBaotaPanelConsole.DeployerConfig{ - ApiUrl: access.ApiUrl, - ApiKey: access.ApiKey, - AutoRestart: maps.GetValueAsBool(options.ProviderDeployConfig, "autoRestart"), + ApiUrl: access.ApiUrl, + ApiKey: access.ApiKey, + AllowInsecureConnections: access.AllowInsecureConnections, + AutoRestart: maps.GetValueAsBool(options.ProviderDeployConfig, "autoRestart"), }) return deployer, err case domain.DeployProviderTypeBaotaPanelSite: deployer, err := pBaotaPanelSite.NewDeployer(&pBaotaPanelSite.DeployerConfig{ - ApiUrl: access.ApiUrl, - ApiKey: access.ApiKey, - SiteType: maps.GetValueOrDefaultAsString(options.ProviderDeployConfig, "siteType", "other"), - SiteName: maps.GetValueAsString(options.ProviderDeployConfig, "siteName"), - SiteNames: slices.Filter(strings.Split(maps.GetValueAsString(options.ProviderDeployConfig, "siteNames"), ";"), func(s string) bool { return s != "" }), + ApiUrl: access.ApiUrl, + ApiKey: access.ApiKey, + AllowInsecureConnections: access.AllowInsecureConnections, + SiteType: maps.GetValueOrDefaultAsString(options.ProviderDeployConfig, "siteType", "other"), + SiteName: maps.GetValueAsString(options.ProviderDeployConfig, "siteName"), + SiteNames: slices.Filter(strings.Split(maps.GetValueAsString(options.ProviderDeployConfig, "siteNames"), ";"), func(s string) bool { return s != "" }), }) return deployer, err @@ -551,10 +598,11 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { } deployer, err := pSafeLine.NewDeployer(&pSafeLine.DeployerConfig{ - ApiUrl: access.ApiUrl, - ApiToken: access.ApiToken, - ResourceType: pSafeLine.ResourceType(maps.GetValueAsString(options.ProviderDeployConfig, "resourceType")), - CertificateId: maps.GetValueAsInt32(options.ProviderDeployConfig, "certificateId"), + ApiUrl: access.ApiUrl, + ApiToken: access.ApiToken, + AllowInsecureConnections: access.AllowInsecureConnections, + ResourceType: pSafeLine.ResourceType(maps.GetValueAsString(options.ProviderDeployConfig, "resourceType")), + CertificateId: maps.GetValueAsInt32(options.ProviderDeployConfig, "certificateId"), }) return deployer, err } @@ -587,7 +635,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { return deployer, err } - case domain.DeployProviderTypeTencentCloudCDN, domain.DeployProviderTypeTencentCloudCLB, domain.DeployProviderTypeTencentCloudCOS, domain.DeployProviderTypeTencentCloudCSS, domain.DeployProviderTypeTencentCloudECDN, domain.DeployProviderTypeTencentCloudEO, domain.DeployProviderTypeTencentCloudSSLDeploy, domain.DeployProviderTypeTencentCloudVOD, domain.DeployProviderTypeTencentCloudWAF: + case domain.DeployProviderTypeTencentCloudCDN, domain.DeployProviderTypeTencentCloudCLB, domain.DeployProviderTypeTencentCloudCOS, domain.DeployProviderTypeTencentCloudCSS, domain.DeployProviderTypeTencentCloudECDN, domain.DeployProviderTypeTencentCloudEO, domain.DeployProviderTypeTencentCloudSCF, domain.DeployProviderTypeTencentCloudSSLDeploy, domain.DeployProviderTypeTencentCloudVOD, domain.DeployProviderTypeTencentCloudWAF: { access := domain.AccessConfigForTencentCloud{} if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { @@ -650,6 +698,15 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { }) return deployer, err + case domain.DeployProviderTypeTencentCloudSCF: + deployer, err := pTencentCloudSCF.NewDeployer(&pTencentCloudSCF.DeployerConfig{ + SecretId: access.SecretId, + SecretKey: access.SecretKey, + Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), + Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + }) + return deployer, err + case domain.DeployProviderTypeTencentCloudSSLDeploy: deployer, err := pTencentCloudSSLDeploy.NewDeployer(&pTencentCloudSSLDeploy.DeployerConfig{ SecretId: access.SecretId, @@ -792,8 +849,9 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { } deployer, err := pWebhook.NewDeployer(&pWebhook.DeployerConfig{ - WebhookUrl: access.Url, - WebhookData: maps.GetValueAsString(options.ProviderDeployConfig, "webhookData"), + WebhookUrl: access.Url, + WebhookData: maps.GetValueAsString(options.ProviderDeployConfig, "webhookData"), + AllowInsecureConnections: access.AllowInsecureConnections, }) return deployer, err } diff --git a/internal/domain/access.go b/internal/domain/access.go index 25df3210..fc6a7eb1 100644 --- a/internal/domain/access.go +++ b/internal/domain/access.go @@ -24,6 +24,12 @@ func (a *Access) UnmarshalConfigToMap() (map[string]any, error) { return config, nil } +type AccessConfigFor1Panel struct { + ApiUrl string `json:"apiUrl"` + ApiKey string `json:"apiKey"` + AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` +} + type AccessConfigForACMEHttpReq struct { Endpoint string `json:"endpoint"` Mode string `json:"mode,omitempty"` @@ -58,8 +64,9 @@ type AccessConfigForBaishan struct { } type AccessConfigForBaotaPanel struct { - ApiUrl string `json:"apiUrl"` - ApiKey string `json:"apiKey"` + ApiUrl string `json:"apiUrl"` + ApiKey string `json:"apiKey"` + AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` } type AccessConfigForBytePlus struct { @@ -169,8 +176,9 @@ type AccessConfigForRainYun struct { } type AccessConfigForSafeLine struct { - ApiUrl string `json:"apiUrl"` - ApiToken string `json:"apiToken"` + ApiUrl string `json:"apiUrl"` + ApiToken string `json:"apiToken"` + AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` } type AccessConfigForSSH struct { @@ -199,7 +207,8 @@ type AccessConfigForVolcEngine struct { } type AccessConfigForWebhook struct { - Url string `json:"url"` + Url string `json:"url"` + AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` } type AccessConfigForWestcn struct { diff --git a/internal/domain/provider.go b/internal/domain/provider.go index 950abc08..78c79d4a 100644 --- a/internal/domain/provider.go +++ b/internal/domain/provider.go @@ -9,7 +9,7 @@ type AccessProviderType string NOTICE: If you add new constant, please keep ASCII order. */ const ( - AccessProviderType1Panel = AccessProviderType("1panel") // 1Panel(预留) + AccessProviderType1Panel = AccessProviderType("1panel") AccessProviderTypeACMEHttpReq = AccessProviderType("acmehttpreq") AccessProviderTypeAkamai = AccessProviderType("akamai") // Akamai(预留) AccessProviderTypeAliyun = AccessProviderType("aliyun") @@ -108,12 +108,15 @@ type DeployProviderType string NOTICE: If you add new constant, please keep ASCII order. */ const ( + DeployProviderType1PanelConsole = DeployProviderType("1panel-console") + DeployProviderType1PanelSite = DeployProviderType("1panel-site") DeployProviderTypeAliyunALB = DeployProviderType("aliyun-alb") DeployProviderTypeAliyunCASDeploy = DeployProviderType("aliyun-casdeploy") DeployProviderTypeAliyunCDN = DeployProviderType("aliyun-cdn") DeployProviderTypeAliyunCLB = DeployProviderType("aliyun-clb") DeployProviderTypeAliyunDCDN = DeployProviderType("aliyun-dcdn") DeployProviderTypeAliyunESA = DeployProviderType("aliyun-esa") + DeployProviderTypeAliyunFC = DeployProviderType("aliyun-fc") DeployProviderTypeAliyunLive = DeployProviderType("aliyun-live") DeployProviderTypeAliyunNLB = DeployProviderType("aliyun-nlb") DeployProviderTypeAliyunOSS = DeployProviderType("aliyun-oss") @@ -149,6 +152,7 @@ const ( DeployProviderTypeTencentCloudCSS = DeployProviderType("tencentcloud-css") DeployProviderTypeTencentCloudECDN = DeployProviderType("tencentcloud-ecdn") DeployProviderTypeTencentCloudEO = DeployProviderType("tencentcloud-eo") + DeployProviderTypeTencentCloudSCF = DeployProviderType("tencentcloud-scf") DeployProviderTypeTencentCloudSSLDeploy = DeployProviderType("tencentcloud-ssldeploy") DeployProviderTypeTencentCloudVOD = DeployProviderType("tencentcloud-vod") DeployProviderTypeTencentCloudWAF = DeployProviderType("tencentcloud-waf") diff --git a/internal/notify/providers.go b/internal/notify/providers.go index 6e18a84c..9cd27439 100644 --- a/internal/notify/providers.go +++ b/internal/notify/providers.go @@ -63,7 +63,8 @@ func createNotifier(channel domain.NotifyChannelType, channelConfig map[string]a case domain.NotifyChannelTypeWebhook: return pWebhook.NewNotifier(&pWebhook.NotifierConfig{ - Url: maps.GetValueAsString(channelConfig, "url"), + Url: maps.GetValueAsString(channelConfig, "url"), + AllowInsecureConnections: maps.GetValueAsBool(channelConfig, "allowInsecureConnections"), }) case domain.NotifyChannelTypeWeCom: diff --git a/internal/pkg/core/deployer/providers/1panel-console/1panel_console.go b/internal/pkg/core/deployer/providers/1panel-console/1panel_console.go new file mode 100644 index 00000000..512b5296 --- /dev/null +++ b/internal/pkg/core/deployer/providers/1panel-console/1panel_console.go @@ -0,0 +1,95 @@ +package onepanelconsole + +import ( + "context" + "crypto/tls" + "errors" + "net/url" + + xerrors "github.com/pkg/errors" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/logger" + opsdk "github.com/usual2970/certimate/internal/pkg/vendors/1panel-sdk" +) + +type DeployerConfig struct { + // 1Panel 地址。 + ApiUrl string `json:"apiUrl"` + // 1Panel 接口密钥。 + ApiKey string `json:"apiKey"` + // 是否允许不安全的连接。 + AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` + // 是否自动重启。 + AutoRestart bool `json:"autoRestart"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger logger.Logger + sdkClient *opsdk.Client +} + +var _ deployer.Deployer = (*DeployerProvider)(nil) + +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { + if config == nil { + panic("config is nil") + } + + client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk client") + } + + return &DeployerProvider{ + config: config, + logger: logger.NewNilLogger(), + sdkClient: client, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { + // 设置面板 SSL 证书 + updateSystemSSLReq := &opsdk.UpdateSystemSSLRequest{ + Cert: certPem, + Key: privkeyPem, + SSL: "enable", + SSLType: "import-paste", + } + if d.config.AutoRestart { + updateSystemSSLReq.AutoRestart = "true" + } else { + updateSystemSSLReq.AutoRestart = "false" + } + updateSystemSSLResp, err := d.sdkClient.UpdateSystemSSL(updateSystemSSLReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request '1panel.UpdateSystemSSL'") + } else { + d.logger.Logt("已设置面板 SSL 证书", updateSystemSSLResp) + } + + return &deployer.DeployResult{}, nil +} + +func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*opsdk.Client, error) { + if _, err := url.Parse(apiUrl); err != nil { + return nil, errors.New("invalid 1panel api url") + } + + if apiKey == "" { + return nil, errors.New("invalid 1panel api key") + } + + client := opsdk.NewClient(apiUrl, apiKey) + if allowInsecure { + client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}) + } + + return client, nil +} diff --git a/internal/pkg/core/deployer/providers/1panel-console/1panel_console_test.go b/internal/pkg/core/deployer/providers/1panel-console/1panel_console_test.go new file mode 100644 index 00000000..d4b7cfa9 --- /dev/null +++ b/internal/pkg/core/deployer/providers/1panel-console/1panel_console_test.go @@ -0,0 +1,72 @@ +package onepanelconsole_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/1panel-console" +) + +var ( + fInputCertPath string + fInputKeyPath string + fApiUrl string + fApiKey string +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_1PANELCONSOLE_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "") + flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "") +} + +/* +Shell command to run this test: + + go test -v ./1panel_console_test.go -args \ + --CERTIMATE_DEPLOYER_1PANELCONSOLE_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_1PANELCONSOLE_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_1PANELCONSOLE_APIURL="http://127.0.0.1:20410" \ + --CERTIMATE_DEPLOYER_1PANELCONSOLE_APIKEY="your-api-key" +*/ +func TestDeploy(t *testing.T) { + flag.Parse() + + t.Run("Deploy", func(t *testing.T) { + t.Log(strings.Join([]string{ + "args:", + fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath), + fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath), + fmt.Sprintf("APIURL: %v", fApiUrl), + fmt.Sprintf("APIKEY: %v", fApiKey), + }, "\n")) + + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + ApiUrl: fApiUrl, + ApiKey: fApiKey, + AllowInsecureConnections: true, + AutoRestart: true, + }) + if err != nil { + t.Errorf("err: %+v", err) + return + } + + fInputCertData, _ := os.ReadFile(fInputCertPath) + fInputKeyData, _ := os.ReadFile(fInputKeyPath) + res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData)) + if err != nil { + t.Errorf("err: %+v", err) + return + } + + t.Logf("ok: %v", res) + }) +} diff --git a/internal/pkg/core/deployer/providers/1panel-site/1panel_site.go b/internal/pkg/core/deployer/providers/1panel-site/1panel_site.go new file mode 100644 index 00000000..cdad354a --- /dev/null +++ b/internal/pkg/core/deployer/providers/1panel-site/1panel_site.go @@ -0,0 +1,127 @@ +package onepanelsite + +import ( + "context" + "crypto/tls" + "errors" + "net/url" + "strconv" + + xerrors "github.com/pkg/errors" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/logger" + "github.com/usual2970/certimate/internal/pkg/core/uploader" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/1panel-ssl" + opsdk "github.com/usual2970/certimate/internal/pkg/vendors/1panel-sdk" +) + +type DeployerConfig struct { + // 1Panel 地址。 + ApiUrl string `json:"apiUrl"` + // 1Panel 接口密钥。 + ApiKey string `json:"apiKey"` + // 是否允许不安全的连接。 + AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` + // 网站 ID。 + WebsiteId int64 `json:"websiteId"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger logger.Logger + sdkClient *opsdk.Client + sslUploader uploader.Uploader +} + +var _ deployer.Deployer = (*DeployerProvider)(nil) + +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { + if config == nil { + panic("config is nil") + } + + client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk client") + } + + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ + ApiUrl: config.ApiUrl, + ApiKey: config.ApiKey, + }) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create ssl uploader") + } + + return &DeployerProvider{ + config: config, + logger: logger.NewNilLogger(), + sdkClient: client, + sslUploader: uploader, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { + // 获取网站 HTTPS 配置 + getHttpsConfReq := &opsdk.GetHttpsConfRequest{ + WebsiteID: d.config.WebsiteId, + } + getHttpsConfResp, err := d.sdkClient.GetHttpsConf(getHttpsConfReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request '1panel.GetHttpsConf'") + } else { + d.logger.Logt("已获取网站 HTTPS 配置", getHttpsConfResp) + } + + // 上传证书到面板 + upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) + if err != nil { + return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Logt("certificate file uploaded", upres) + } + + // 修改网站 HTTPS 配置 + certId, _ := strconv.ParseInt(upres.CertId, 10, 64) + updateHttpsConfReq := &opsdk.UpdateHttpsConfRequest{ + WebsiteID: d.config.WebsiteId, + Type: "existed", + WebsiteSSLID: certId, + Enable: getHttpsConfResp.Data.Enable, + HttpConfig: getHttpsConfResp.Data.HttpConfig, + SSLProtocol: getHttpsConfResp.Data.SSLProtocol, + Algorithm: getHttpsConfResp.Data.Algorithm, + Hsts: getHttpsConfResp.Data.Hsts, + } + updateHttpsConfResp, err := d.sdkClient.UpdateHttpsConf(updateHttpsConfReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request '1panel.UpdateHttpsConf'") + } else { + d.logger.Logt("已获取网站 HTTPS 配置", updateHttpsConfResp) + } + + return &deployer.DeployResult{}, nil +} + +func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*opsdk.Client, error) { + if _, err := url.Parse(apiUrl); err != nil { + return nil, errors.New("invalid 1panel api url") + } + + if apiKey == "" { + return nil, errors.New("invalid 1panel api key") + } + + client := opsdk.NewClient(apiUrl, apiKey) + if allowInsecure { + client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}) + } + + return client, nil +} diff --git a/internal/pkg/core/deployer/providers/1panel-site/1panel_site_test.go b/internal/pkg/core/deployer/providers/1panel-site/1panel_site_test.go new file mode 100644 index 00000000..1be2444d --- /dev/null +++ b/internal/pkg/core/deployer/providers/1panel-site/1panel_site_test.go @@ -0,0 +1,76 @@ +package onepanelsite_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/1panel-site" +) + +var ( + fInputCertPath string + fInputKeyPath string + fApiUrl string + fApiKey string + fWebsiteId int64 +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_1PANELCONSOLE_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "") + flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "") + flag.Int64Var(&fWebsiteId, argsPrefix+"WEBSITEID", 0, "") +} + +/* +Shell command to run this test: + + go test -v ./1panel_console_test.go -args \ + --CERTIMATE_DEPLOYER_1PANELCONSOLE_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_1PANELCONSOLE_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_1PANELCONSOLE_APIURL="http://127.0.0.1:20410" \ + --CERTIMATE_DEPLOYER_1PANELCONSOLE_APIKEY="your-api-key" \ + --CERTIMATE_DEPLOYER_1PANELCONSOLE_WEBSITEID="your-website-id" +*/ +func TestDeploy(t *testing.T) { + flag.Parse() + + t.Run("Deploy", func(t *testing.T) { + t.Log(strings.Join([]string{ + "args:", + fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath), + fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath), + fmt.Sprintf("APIURL: %v", fApiUrl), + fmt.Sprintf("APIKEY: %v", fApiKey), + fmt.Sprintf("WEBSITEID: %v", fWebsiteId), + }, "\n")) + + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + ApiUrl: fApiUrl, + ApiKey: fApiKey, + WebsiteId: fWebsiteId, + AllowInsecureConnections: true, + }) + if err != nil { + t.Errorf("err: %+v", err) + return + } + + fInputCertData, _ := os.ReadFile(fInputCertPath) + fInputKeyData, _ := os.ReadFile(fInputKeyPath) + res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData)) + if err != nil { + t.Errorf("err: %+v", err) + return + } + + t.Logf("ok: %v", res) + }) +} diff --git a/internal/pkg/core/deployer/providers/aliyun-alb/aliyun_alb.go b/internal/pkg/core/deployer/providers/aliyun-alb/aliyun_alb.go index 39600c7b..4388fbf0 100644 --- a/internal/pkg/core/deployer/providers/aliyun-alb/aliyun_alb.go +++ b/internal/pkg/core/deployer/providers/aliyun-alb/aliyun_alb.go @@ -386,7 +386,7 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL } func createSdkClients(accessKeyId, accessKeySecret, region string) (*wSdkClients, error) { - // 接入点一览 https://www.alibabacloud.com/help/zh/slb/application-load-balancer/developer-reference/api-alb-2020-06-16-albEndpoint + // 接入点一览 https://api.aliyun.com/product/Alb var albEndpoint string switch region { case "cn-hangzhou-finance": @@ -405,7 +405,7 @@ func createSdkClients(accessKeyId, accessKeySecret, region string) (*wSdkClients return nil, err } - // 接入点一览 https://help.aliyun.com/zh/ssl-certificate/developer-reference/endpoints + // 接入点一览 https://api.aliyun.com/product/cas var casEndpoint string if !strings.HasPrefix(region, "cn-") { casEndpoint = "cas.ap-southeast-1.aliyuncs.com" diff --git a/internal/pkg/core/deployer/providers/aliyun-cas-deploy/aliyun_cas_deploy.go b/internal/pkg/core/deployer/providers/aliyun-cas-deploy/aliyun_cas_deploy.go index 1cc36c6f..fa045521 100644 --- a/internal/pkg/core/deployer/providers/aliyun-cas-deploy/aliyun_cas_deploy.go +++ b/internal/pkg/core/deployer/providers/aliyun-cas-deploy/aliyun_cas_deploy.go @@ -151,7 +151,7 @@ func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunCas.Cl region = "cn-hangzhou" // CAS 服务默认区域:华东一杭州 } - // 接入点一览 https://help.aliyun.com/zh/ssl-certificate/developer-reference/endpoints + // 接入点一览 https://api.aliyun.com/product/cas var endpoint string switch region { case "cn-hangzhou": diff --git a/internal/pkg/core/deployer/providers/aliyun-clb/aliyun_clb.go b/internal/pkg/core/deployer/providers/aliyun-clb/aliyun_clb.go index 21a1e471..304a7131 100644 --- a/internal/pkg/core/deployer/providers/aliyun-clb/aliyun_clb.go +++ b/internal/pkg/core/deployer/providers/aliyun-clb/aliyun_clb.go @@ -274,7 +274,7 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL } func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunSlb.Client, error) { - // 接入点一览 https://help.aliyun.com/zh/slb/classic-load-balancer/developer-reference/api-slb-2014-05-15-endpoint + // 接入点一览 https://api.aliyun.com/product/Slb var endpoint string switch region { case diff --git a/internal/pkg/core/deployer/providers/aliyun-esa/aliyun_esa.go b/internal/pkg/core/deployer/providers/aliyun-esa/aliyun_esa.go index 1ccbdae5..5134d115 100644 --- a/internal/pkg/core/deployer/providers/aliyun-esa/aliyun_esa.go +++ b/internal/pkg/core/deployer/providers/aliyun-esa/aliyun_esa.go @@ -98,7 +98,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe } func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunEsa.Client, error) { - // 接入点一览 https://help.aliyun.com/zh/edge-security-acceleration/esa/api-esa-2024-09-10-endpoint + // 接入点一览 https://api.aliyun.com/product/ESA config := &aliyunOpen.Config{ AccessKeyId: tea.String(accessKeyId), AccessKeySecret: tea.String(accessKeySecret), diff --git a/internal/pkg/core/deployer/providers/aliyun-esa/aliyun_esa_test.go b/internal/pkg/core/deployer/providers/aliyun-esa/aliyun_esa_test.go index c2d81aa3..9a2c4ca0 100644 --- a/internal/pkg/core/deployer/providers/aliyun-esa/aliyun_esa_test.go +++ b/internal/pkg/core/deployer/providers/aliyun-esa/aliyun_esa_test.go @@ -39,7 +39,7 @@ Shell command to run this test: --CERTIMATE_DEPLOYER_ALIYUNESA_INPUTKEYPATH="/path/to/your-input-key.pem" \ --CERTIMATE_DEPLOYER_ALIYUNESA_ACCESSKEYID="your-access-key-id" \ --CERTIMATE_DEPLOYER_ALIYUNESA_ACCESSKEYSECRET="your-access-key-secret" \ - --CERTIMATE_DEPLOYER_ALIYUNOSS_REGION="cn-hangzhou" \ + --CERTIMATE_DEPLOYER_ALIYUNESA_REGION="cn-hangzhou" \ --CERTIMATE_DEPLOYER_ALIYUNESA_SITEID="your-esa-site-id" */ func TestDeploy(t *testing.T) { diff --git a/internal/pkg/core/deployer/providers/aliyun-fc/aliyun_fc.go b/internal/pkg/core/deployer/providers/aliyun-fc/aliyun_fc.go new file mode 100644 index 00000000..e70931f8 --- /dev/null +++ b/internal/pkg/core/deployer/providers/aliyun-fc/aliyun_fc.go @@ -0,0 +1,186 @@ +package aliyunfc + +import ( + "context" + "fmt" + "time" + + aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client" + aliyunFc3 "github.com/alibabacloud-go/fc-20230330/v4/client" + aliyunFc2 "github.com/alibabacloud-go/fc-open-20210406/v2/client" + "github.com/alibabacloud-go/tea/tea" + xerrors "github.com/pkg/errors" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/logger" +) + +type DeployerConfig struct { + // 阿里云 AccessKeyId。 + AccessKeyId string `json:"accessKeyId"` + // 阿里云 AccessKeySecret。 + AccessKeySecret string `json:"accessKeySecret"` + // 阿里云地域。 + Region string `json:"region"` + // 服务版本。 + // 零值时默认为 "3.0"。 + ServiceVersion string `json:"serviceVersion"` + // 自定义域名(不支持泛域名)。 + Domain string `json:"domain"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger logger.Logger + sdkClients *wSdkClients +} + +var _ deployer.Deployer = (*DeployerProvider)(nil) + +type wSdkClients struct { + fc2 *aliyunFc2.Client + fc3 *aliyunFc3.Client +} + +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { + if config == nil { + panic("config is nil") + } + + clients, err := createSdkClients(config.AccessKeyId, config.AccessKeySecret, config.Region) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk clients") + } + + return &DeployerProvider{ + config: config, + logger: logger.NewNilLogger(), + sdkClients: clients, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { + switch d.config.ServiceVersion { + case "", "3.0": + if err := d.deployToFC3(ctx, certPem, privkeyPem); err != nil { + return nil, err + } + + case "2.0": + if err := d.deployToFC2(ctx, certPem, privkeyPem); err != nil { + return nil, err + } + + default: + return nil, xerrors.Errorf("unsupported service version: %s", d.config.ServiceVersion) + } + + return &deployer.DeployResult{}, nil +} + +func (d *DeployerProvider) deployToFC3(ctx context.Context, certPem string, privkeyPem string) error { + // 获取自定义域名 + // REF: https://help.aliyun.com/zh/functioncompute/fc-3-0/developer-reference/api-fc-2023-03-30-getcustomdomain + getCustomDomainResp, err := d.sdkClients.fc3.GetCustomDomain(tea.String(d.config.Domain)) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'fc.GetCustomDomain'") + } else { + d.logger.Logt("已获取自定义域名", getCustomDomainResp) + } + + // 更新自定义域名 + // REF: https://help.aliyun.com/zh/functioncompute/fc-3-0/developer-reference/api-fc-2023-03-30-updatecustomdomain + updateCustomDomainReq := &aliyunFc3.UpdateCustomDomainRequest{ + Body: &aliyunFc3.UpdateCustomDomainInput{ + CertConfig: &aliyunFc3.CertConfig{ + CertName: tea.String(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())), + Certificate: tea.String(certPem), + PrivateKey: tea.String(privkeyPem), + }, + Protocol: getCustomDomainResp.Body.Protocol, + TlsConfig: getCustomDomainResp.Body.TlsConfig, + }, + } + updateCustomDomainResp, err := d.sdkClients.fc3.UpdateCustomDomain(tea.String(d.config.Domain), updateCustomDomainReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'fc.UpdateCustomDomain'") + } else { + d.logger.Logt("已更新自定义域名", updateCustomDomainResp) + } + + return nil +} + +func (d *DeployerProvider) deployToFC2(ctx context.Context, certPem string, privkeyPem string) error { + // 获取自定义域名 + // REF: https://help.aliyun.com/zh/functioncompute/fc-2-0/developer-reference/api-fc-open-2021-04-06-getcustomdomain + getCustomDomainResp, err := d.sdkClients.fc2.GetCustomDomain(tea.String(d.config.Domain)) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'fc.GetCustomDomain'") + } else { + d.logger.Logt("已获取自定义域名", getCustomDomainResp) + } + + // 更新自定义域名 + // REF: https://help.aliyun.com/zh/functioncompute/fc-2-0/developer-reference/api-fc-open-2021-04-06-updatecustomdomain + updateCustomDomainReq := &aliyunFc2.UpdateCustomDomainRequest{ + CertConfig: &aliyunFc2.CertConfig{ + CertName: tea.String(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())), + Certificate: tea.String(certPem), + PrivateKey: tea.String(privkeyPem), + }, + Protocol: getCustomDomainResp.Body.Protocol, + TlsConfig: getCustomDomainResp.Body.TlsConfig, + } + updateCustomDomainResp, err := d.sdkClients.fc2.UpdateCustomDomain(tea.String(d.config.Domain), updateCustomDomainReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'fc.UpdateCustomDomain'") + } else { + d.logger.Logt("已更新自定义域名", updateCustomDomainResp) + } + + return nil +} + +func createSdkClients(accessKeyId, accessKeySecret, region string) (*wSdkClients, error) { + // 接入点一览 https://api.aliyun.com/product/FC-Open + var fc2Endpoint string + switch region { + case "cn-hangzhou-finance": + fc2Endpoint = fmt.Sprintf("%s.fc.aliyuncs.com", region) + default: + fc2Endpoint = fmt.Sprintf("fc.%s.aliyuncs.com", region) + } + + fc2Config := &aliyunOpen.Config{ + AccessKeyId: tea.String(accessKeyId), + AccessKeySecret: tea.String(accessKeySecret), + Endpoint: tea.String(fc2Endpoint), + } + fc2Client, err := aliyunFc2.NewClient(fc2Config) + if err != nil { + return nil, err + } + + // 接入点一览 https://api.aliyun.com/product/FC-Open + fc3Endpoint := fmt.Sprintf("fcv3.%s.aliyuncs.com", region) + fc3Config := &aliyunOpen.Config{ + AccessKeyId: tea.String(accessKeyId), + AccessKeySecret: tea.String(accessKeySecret), + Endpoint: tea.String(fc3Endpoint), + } + fc3Client, err := aliyunFc3.NewClient(fc3Config) + if err != nil { + return nil, err + } + + return &wSdkClients{ + fc2: fc2Client, + fc3: fc3Client, + }, nil +} diff --git a/internal/pkg/core/deployer/providers/aliyun-fc/aliyun_fc_test.go b/internal/pkg/core/deployer/providers/aliyun-fc/aliyun_fc_test.go new file mode 100644 index 00000000..a8780285 --- /dev/null +++ b/internal/pkg/core/deployer/providers/aliyun-fc/aliyun_fc_test.go @@ -0,0 +1,80 @@ +package aliyunfc_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-fc" +) + +var ( + fInputCertPath string + fInputKeyPath string + fAccessKeyId string + fAccessKeySecret string + fRegion string + fSiteId int64 +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_ALIYUNFC_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "") + flag.StringVar(&fAccessKeySecret, argsPrefix+"ACCESSKEYSECRET", "", "") + flag.StringVar(&fRegion, argsPrefix+"REGION", "", "") + flag.Int64Var(&fSiteId, argsPrefix+"SITEID", "", "") +} + +/* +Shell command to run this test: + + go test -v ./aliyun_fc_test.go -args \ + --CERTIMATE_DEPLOYER_ALIYUNFC_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_ALIYUNFC_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_ALIYUNFC_ACCESSKEYID="your-access-key-id" \ + --CERTIMATE_DEPLOYER_ALIYUNFC_ACCESSKEYSECRET="your-access-key-secret" \ + --CERTIMATE_DEPLOYER_ALIYUNFC_REGION="cn-hangzhou" \ + --CERTIMATE_DEPLOYER_ALIYUNFC_SITEID="your-fc-site-id" +*/ +func TestDeploy(t *testing.T) { + flag.Parse() + + t.Run("Deploy", func(t *testing.T) { + t.Log(strings.Join([]string{ + "args:", + fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath), + fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath), + fmt.Sprintf("ACCESSKEYID: %v", fAccessKeyId), + fmt.Sprintf("ACCESSKEYSECRET: %v", fAccessKeySecret), + fmt.Sprintf("REGION: %v", fRegion), + fmt.Sprintf("SITEID: %v", fSiteId), + }, "\n")) + + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + AccessKeyId: fAccessKeyId, + AccessKeySecret: fAccessKeySecret, + Region: fRegion, + SiteId: fSiteId, + }) + if err != nil { + t.Errorf("err: %+v", err) + return + } + + fInputCertData, _ := os.ReadFile(fInputCertPath) + fInputKeyData, _ := os.ReadFile(fInputKeyPath) + res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData)) + if err != nil { + t.Errorf("err: %+v", err) + return + } + + t.Logf("ok: %v", res) + }) +} diff --git a/internal/pkg/core/deployer/providers/aliyun-live/aliyun_live.go b/internal/pkg/core/deployer/providers/aliyun-live/aliyun_live.go index 5735da79..99b06aca 100644 --- a/internal/pkg/core/deployer/providers/aliyun-live/aliyun_live.go +++ b/internal/pkg/core/deployer/providers/aliyun-live/aliyun_live.go @@ -81,7 +81,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe } func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunLive.Client, error) { - // 接入点一览 https://help.aliyun.com/zh/live/developer-reference/api-live-2016-11-01-endpoint + // 接入点一览 https://api.aliyun.com/product/live var endpoint string switch region { case diff --git a/internal/pkg/core/deployer/providers/aliyun-nlb/aliyun_nlb.go b/internal/pkg/core/deployer/providers/aliyun-nlb/aliyun_nlb.go index 0f1f1bca..8dc1b2e3 100644 --- a/internal/pkg/core/deployer/providers/aliyun-nlb/aliyun_nlb.go +++ b/internal/pkg/core/deployer/providers/aliyun-nlb/aliyun_nlb.go @@ -211,7 +211,7 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL } func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunNlb.Client, error) { - // 接入点一览 https://help.aliyun.com/zh/slb/network-load-balancer/developer-reference/api-nlb-2022-04-30-endpoint + // 接入点一览 https://api.aliyun.com/product/Nlb var endpoint string switch region { default: diff --git a/internal/pkg/core/deployer/providers/aliyun-oss/aliyun_oss.go b/internal/pkg/core/deployer/providers/aliyun-oss/aliyun_oss.go index 88adbf0b..3eba5c55 100644 --- a/internal/pkg/core/deployer/providers/aliyun-oss/aliyun_oss.go +++ b/internal/pkg/core/deployer/providers/aliyun-oss/aliyun_oss.go @@ -81,7 +81,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe } func createSdkClient(accessKeyId, accessKeySecret, region string) (*oss.Client, error) { - // 接入点一览 https://help.aliyun.com/zh/oss/user-guide/regions-and-endpoints + // 接入点一览 https://api.aliyun.com/product/Oss var endpoint string switch region { case "": diff --git a/internal/pkg/core/deployer/providers/aliyun-vod/aliyun_vod.go b/internal/pkg/core/deployer/providers/aliyun-vod/aliyun_vod.go index 740fbb56..77c2ebf0 100644 --- a/internal/pkg/core/deployer/providers/aliyun-vod/aliyun_vod.go +++ b/internal/pkg/core/deployer/providers/aliyun-vod/aliyun_vod.go @@ -77,7 +77,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe } func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunVod.Client, error) { - // 接入点一览 https://help.aliyun.com/zh/vod/developer-reference/api-vod-2017-03-21-endpoint + // 接入点一览 https://api.aliyun.com/product/vod endpoint := fmt.Sprintf("vod.%s.aliyuncs.com", region) config := &aliyunOpen.Config{ diff --git a/internal/pkg/core/deployer/providers/aliyun-waf/aliyun_waf.go b/internal/pkg/core/deployer/providers/aliyun-waf/aliyun_waf.go index 5747d23e..ccb9adc6 100644 --- a/internal/pkg/core/deployer/providers/aliyun-waf/aliyun_waf.go +++ b/internal/pkg/core/deployer/providers/aliyun-waf/aliyun_waf.go @@ -111,7 +111,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe } func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunWaf.Client, error) { - // 接入点一览:https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-endpoint + // 接入点一览:https://api.aliyun.com/product/waf-openapi config := &aliyunOpen.Config{ AccessKeyId: tea.String(accessKeyId), AccessKeySecret: tea.String(accessKeySecret), diff --git a/internal/pkg/core/deployer/providers/aliyun-waf/aliyun_waf_test.go b/internal/pkg/core/deployer/providers/aliyun-waf/aliyun_waf_test.go index 06a76c63..2668db47 100644 --- a/internal/pkg/core/deployer/providers/aliyun-waf/aliyun_waf_test.go +++ b/internal/pkg/core/deployer/providers/aliyun-waf/aliyun_waf_test.go @@ -39,7 +39,7 @@ Shell command to run this test: --CERTIMATE_DEPLOYER_ALIYUNWAF_INPUTKEYPATH="/path/to/your-input-key.pem" \ --CERTIMATE_DEPLOYER_ALIYUNWAF_ACCESSKEYID="your-access-key-id" \ --CERTIMATE_DEPLOYER_ALIYUNWAF_ACCESSKEYSECRET="your-access-key-secret" \ - --CERTIMATE_DEPLOYER_ALIYUNOSS_REGION="cn-hangzhou" \ + --CERTIMATE_DEPLOYER_ALIYUNWAF_REGION="cn-hangzhou" \ --CERTIMATE_DEPLOYER_ALIYUNWAF_INSTANCEID="your-waf-instance-id" */ func TestDeploy(t *testing.T) { diff --git a/internal/pkg/core/deployer/providers/baotapanel-console/baotapanel_console.go b/internal/pkg/core/deployer/providers/baotapanel-console/baotapanel_console.go index 6343acf7..ff09dc26 100644 --- a/internal/pkg/core/deployer/providers/baotapanel-console/baotapanel_console.go +++ b/internal/pkg/core/deployer/providers/baotapanel-console/baotapanel_console.go @@ -2,6 +2,7 @@ import ( "context" + "crypto/tls" "errors" "net/url" @@ -17,6 +18,8 @@ type DeployerConfig struct { ApiUrl string `json:"apiUrl"` // 宝塔面板接口密钥。 ApiKey string `json:"apiKey"` + // 是否允许不安全的连接。 + AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` // 是否自动重启。 AutoRestart bool `json:"autoRestart"` } @@ -34,7 +37,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { panic("config is nil") } - client, err := createSdkClient(config.ApiUrl, config.ApiKey) + client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections) if err != nil { return nil, xerrors.Wrap(err, "failed to create sdk client") } @@ -65,21 +68,18 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe } if d.config.AutoRestart { - // 重启面板 + // 重启面板(无需关心响应,因为宝塔重启时会断开连接产生 error) systemServiceAdminReq := &btsdk.SystemServiceAdminRequest{ Name: "nginx", Type: "restart", } - _, err := d.sdkClient.SystemServiceAdmin(systemServiceAdminReq) - if err != nil { - return nil, xerrors.Wrap(err, "failed to execute sdk request 'bt.SystemServiceAdmin'") - } + d.sdkClient.SystemServiceAdmin(systemServiceAdminReq) } return &deployer.DeployResult{}, nil } -func createSdkClient(apiUrl, apiKey string) (*btsdk.Client, error) { +func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*btsdk.Client, error) { if _, err := url.Parse(apiUrl); err != nil { return nil, errors.New("invalid baota api url") } @@ -89,5 +89,9 @@ func createSdkClient(apiUrl, apiKey string) (*btsdk.Client, error) { } client := btsdk.NewClient(apiUrl, apiKey) + if allowInsecure { + client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}) + } + return client, nil } diff --git a/internal/pkg/core/deployer/providers/baotapanel-console/baotapanel_console_test.go b/internal/pkg/core/deployer/providers/baotapanel-console/baotapanel_console_test.go index 06a2f096..a10afb37 100644 --- a/internal/pkg/core/deployer/providers/baotapanel-console/baotapanel_console_test.go +++ b/internal/pkg/core/deployer/providers/baotapanel-console/baotapanel_console_test.go @@ -49,8 +49,10 @@ func TestDeploy(t *testing.T) { }, "\n")) deployer, err := provider.NewDeployer(&provider.DeployerConfig{ - ApiUrl: fApiUrl, - ApiKey: fApiKey, + ApiUrl: fApiUrl, + ApiKey: fApiKey, + AllowInsecureConnections: true, + AutoRestart: true, }) if err != nil { t.Errorf("err: %+v", err) diff --git a/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site.go b/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site.go index 62cef9de..c6bf4966 100644 --- a/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site.go +++ b/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site.go @@ -2,6 +2,7 @@ import ( "context" + "crypto/tls" "errors" "fmt" "net/url" @@ -19,6 +20,8 @@ type DeployerConfig struct { ApiUrl string `json:"apiUrl"` // 宝塔面板接口密钥。 ApiKey string `json:"apiKey"` + // 是否允许不安全的连接。 + AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` // 站点类型。 SiteType string `json:"siteType"` // 站点名称(单个)。 @@ -40,7 +43,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { panic("config is nil") } - client, err := createSdkClient(config.ApiUrl, config.ApiKey) + client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections) if err != nil { return nil, xerrors.Wrap(err, "failed to create sdk client") } @@ -122,7 +125,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe return &deployer.DeployResult{}, nil } -func createSdkClient(apiUrl, apiKey string) (*btsdk.Client, error) { +func createSdkClient(apiUrl, apiKey string, allowInsecure bool) (*btsdk.Client, error) { if _, err := url.Parse(apiUrl); err != nil { return nil, errors.New("invalid baota api url") } @@ -132,5 +135,9 @@ func createSdkClient(apiUrl, apiKey string) (*btsdk.Client, error) { } client := btsdk.NewClient(apiUrl, apiKey) + if allowInsecure { + client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}) + } + return client, nil } diff --git a/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site_test.go b/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site_test.go index 4c31b021..f36605fe 100644 --- a/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site_test.go +++ b/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site_test.go @@ -57,11 +57,12 @@ func TestDeploy(t *testing.T) { }, "\n")) deployer, err := provider.NewDeployer(&provider.DeployerConfig{ - ApiUrl: fApiUrl, - ApiKey: fApiKey, - SiteType: fSiteType, - SiteName: fSiteName, - SiteNames: []string{fSiteName}, + ApiUrl: fApiUrl, + ApiKey: fApiKey, + AllowInsecureConnections: true, + SiteType: fSiteType, + SiteName: fSiteName, + SiteNames: []string{fSiteName}, }) if err != nil { t.Errorf("err: %+v", err) diff --git a/internal/pkg/core/deployer/providers/safeline/safeline.go b/internal/pkg/core/deployer/providers/safeline/safeline.go index 3b4006c4..d0186100 100644 --- a/internal/pkg/core/deployer/providers/safeline/safeline.go +++ b/internal/pkg/core/deployer/providers/safeline/safeline.go @@ -2,6 +2,7 @@ import ( "context" + "crypto/tls" "errors" "fmt" "net/url" @@ -18,6 +19,8 @@ type DeployerConfig struct { ApiUrl string `json:"apiUrl"` // 雷池 API Token。 ApiToken string `json:"apiToken"` + // 是否允许不安全的连接。 + AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` // 部署资源类型。 ResourceType ResourceType `json:"resourceType"` // 证书 ID。 @@ -38,9 +41,9 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { panic("config is nil") } - client, err := createSdkClient(config.ApiUrl, config.ApiToken) + client, err := createSdkClient(config.ApiUrl, config.ApiToken, config.AllowInsecureConnections) if err != nil { - return nil, xerrors.Wrap(err, "failed to create sdk clients") + return nil, xerrors.Wrap(err, "failed to create sdk client") } return &DeployerProvider{ @@ -94,7 +97,7 @@ func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPem stri return nil } -func createSdkClient(apiUrl, apiToken string) (*safelinesdk.Client, error) { +func createSdkClient(apiUrl, apiToken string, allowInsecure bool) (*safelinesdk.Client, error) { if _, err := url.Parse(apiUrl); err != nil { return nil, errors.New("invalid safeline api url") } @@ -104,5 +107,9 @@ func createSdkClient(apiUrl, apiToken string) (*safelinesdk.Client, error) { } client := safelinesdk.NewClient(apiUrl, apiToken) + if allowInsecure { + client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}) + } + return client, nil } diff --git a/internal/pkg/core/deployer/providers/safeline/safeline_test.go b/internal/pkg/core/deployer/providers/safeline/safeline_test.go index 0d7f2223..42c6313f 100644 --- a/internal/pkg/core/deployer/providers/safeline/safeline_test.go +++ b/internal/pkg/core/deployer/providers/safeline/safeline_test.go @@ -53,10 +53,11 @@ func TestDeploy(t *testing.T) { }, "\n")) deployer, err := provider.NewDeployer(&provider.DeployerConfig{ - ApiUrl: fApiUrl, - ApiToken: fApiToken, - ResourceType: provider.ResourceType("certificate"), - CertificateId: fCertificateId, + ApiUrl: fApiUrl, + ApiToken: fApiToken, + AllowInsecureConnections: true, + ResourceType: provider.ResourceType("certificate"), + CertificateId: int32(fCertificateId), }) if err != nil { t.Errorf("err: %+v", err) diff --git a/internal/pkg/core/deployer/providers/tencentcloud-cos/tencentcloud_cos.go b/internal/pkg/core/deployer/providers/tencentcloud-cos/tencentcloud_cos.go index d3b3f881..becceab6 100644 --- a/internal/pkg/core/deployer/providers/tencentcloud-cos/tencentcloud_cos.go +++ b/internal/pkg/core/deployer/providers/tencentcloud-cos/tencentcloud_cos.go @@ -45,7 +45,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { client, err := createSdkClient(config.SecretId, config.SecretKey, config.Region) if err != nil { - return nil, xerrors.Wrap(err, "failed to create sdk clients") + return nil, xerrors.Wrap(err, "failed to create sdk client") } uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ diff --git a/internal/pkg/core/deployer/providers/tencentcloud-scf/tencentcloud_scf.go b/internal/pkg/core/deployer/providers/tencentcloud-scf/tencentcloud_scf.go new file mode 100644 index 00000000..3a3aeb82 --- /dev/null +++ b/internal/pkg/core/deployer/providers/tencentcloud-scf/tencentcloud_scf.go @@ -0,0 +1,114 @@ +package tencentcloudscf + +import ( + "context" + + xerrors "github.com/pkg/errors" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile" + tcScf "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf/v20180416" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/logger" + "github.com/usual2970/certimate/internal/pkg/core/uploader" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl" +) + +type DeployerConfig struct { + // 腾讯云 SecretId。 + SecretId string `json:"secretId"` + // 腾讯云 SecretKey。 + SecretKey string `json:"secretKey"` + // 腾讯云地域。 + Region string `json:"region"` + // 自定义域名(不支持泛域名)。 + Domain string `json:"domain"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger logger.Logger + sdkClient *tcScf.Client + sslUploader uploader.Uploader +} + +var _ deployer.Deployer = (*DeployerProvider)(nil) + +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { + if config == nil { + panic("config is nil") + } + + client, err := createSdkClient(config.SecretId, config.SecretKey, config.Region) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk client") + } + + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ + SecretId: config.SecretId, + SecretKey: config.SecretKey, + }) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create ssl uploader") + } + + return &DeployerProvider{ + config: config, + logger: logger.NewNilLogger(), + sdkClient: client, + sslUploader: uploader, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { + // 查看云函数自定义域名详情 + // REF: https://cloud.tencent.com/document/product/583/111924 + getCustomDomainReq := tcScf.NewGetCustomDomainRequest() + getCustomDomainReq.Domain = common.StringPtr(d.config.Domain) + getCustomDomainResp, err := d.sdkClient.GetCustomDomain(getCustomDomainReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'scf.GetCustomDomain'") + } else { + d.logger.Logt("已查看云函数自定义域名详情", getCustomDomainResp.Response) + } + + // 上传证书到 SSL + upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) + if err != nil { + return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Logt("certificate file uploaded", upres) + } + + // 更新云函数自定义域名 + // REF: https://cloud.tencent.com/document/product/583/111922 + updateCustomDomainReq := tcScf.NewUpdateCustomDomainRequest() + updateCustomDomainReq.Domain = common.StringPtr(d.config.Domain) + updateCustomDomainReq.CertConfig = &tcScf.CertConf{ + CertificateId: common.StringPtr(upres.CertId), + } + updateCustomDomainReq.Protocol = getCustomDomainResp.Response.Protocol + updateCustomDomainResp, err := d.sdkClient.UpdateCustomDomain(updateCustomDomainReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'scf.UpdateCustomDomain'") + } else { + d.logger.Logt("已设置点播域名 HTTPS 证书", updateCustomDomainResp.Response) + } + + return &deployer.DeployResult{}, nil +} + +func createSdkClient(secretId, secretKey, region string) (*tcScf.Client, error) { + credential := common.NewCredential(secretId, secretKey) + client, err := tcScf.NewClient(credential, region, profile.NewClientProfile()) + if err != nil { + return nil, err + } + + return client, nil +} diff --git a/internal/pkg/core/deployer/providers/tencentcloud-scf/tencentcloud_scf_test.go b/internal/pkg/core/deployer/providers/tencentcloud-scf/tencentcloud_scf_test.go new file mode 100644 index 00000000..84a1ad79 --- /dev/null +++ b/internal/pkg/core/deployer/providers/tencentcloud-scf/tencentcloud_scf_test.go @@ -0,0 +1,80 @@ +package tencentcloudscf_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-scf" +) + +var ( + fInputCertPath string + fInputKeyPath string + fSecretId string + fSecretKey string + fRegion string + fDomain string +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_TENCENTCLOUDSCF_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fSecretId, argsPrefix+"SECRETID", "", "") + flag.StringVar(&fSecretKey, argsPrefix+"SECRETKEY", "", "") + flag.StringVar(&fRegion, argsPrefix+"REGION", "", "") + flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "") +} + +/* +Shell command to run this test: + + go test -v ./tencentcloud_scf_test.go -args \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDSCF_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDSCF_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDSCF_SECRETID="your-secret-id" \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDSCF_SECRETKEY="your-secret-key" \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDSCF_REGION="ap-guangzhou" \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDSCF_DOMAIN="example.com" +*/ +func TestDeploy(t *testing.T) { + flag.Parse() + + t.Run("Deploy", func(t *testing.T) { + t.Log(strings.Join([]string{ + "args:", + fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath), + fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath), + fmt.Sprintf("SECRETID: %v", fSecretId), + fmt.Sprintf("SECRETKEY: %v", fSecretKey), + fmt.Sprintf("REGION: %v", fRegion), + fmt.Sprintf("DOMAIN: %v", fDomain), + }, "\n")) + + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + SecretId: fSecretId, + SecretKey: fSecretKey, + Region: fRegion, + Domain: fDomain, + }) + if err != nil { + t.Errorf("err: %+v", err) + return + } + + fInputCertData, _ := os.ReadFile(fInputCertPath) + fInputKeyData, _ := os.ReadFile(fInputKeyPath) + res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData)) + if err != nil { + t.Errorf("err: %+v", err) + return + } + + t.Logf("ok: %v", res) + }) +} diff --git a/internal/pkg/core/deployer/providers/tencentcloud-vod/tencentcloud_vod.go b/internal/pkg/core/deployer/providers/tencentcloud-vod/tencentcloud_vod.go index fbce8d6f..77177469 100644 --- a/internal/pkg/core/deployer/providers/tencentcloud-vod/tencentcloud_vod.go +++ b/internal/pkg/core/deployer/providers/tencentcloud-vod/tencentcloud_vod.go @@ -41,7 +41,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { client, err := createSdkClient(config.SecretId, config.SecretKey) if err != nil { - return nil, xerrors.Wrap(err, "failed to create sdk clients") + return nil, xerrors.Wrap(err, "failed to create sdk client") } uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ diff --git a/internal/pkg/core/deployer/providers/tencentcloud-vod/tencentcloud_vod_test.go b/internal/pkg/core/deployer/providers/tencentcloud-vod/tencentcloud_vod_test.go index 60871a31..ffd085cd 100644 --- a/internal/pkg/core/deployer/providers/tencentcloud-vod/tencentcloud_vod_test.go +++ b/internal/pkg/core/deployer/providers/tencentcloud-vod/tencentcloud_vod_test.go @@ -16,7 +16,6 @@ var ( fInputKeyPath string fSecretId string fSecretKey string - fRegion string fDomain string fSubAppId int64 fInstanceId string @@ -29,7 +28,6 @@ func init() { flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") flag.StringVar(&fSecretId, argsPrefix+"SECRETID", "", "") flag.StringVar(&fSecretKey, argsPrefix+"SECRETKEY", "", "") - flag.StringVar(&fRegion, argsPrefix+"REGION", "", "") flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "") flag.Int64Var(&fSubAppId, argsPrefix+"SUBAPPID", 0, "") flag.StringVar(&fInstanceId, argsPrefix+"INSTANCEID", "", "") @@ -43,7 +41,6 @@ Shell command to run this test: --CERTIMATE_DEPLOYER_TENCENTCLOUDVOD_INPUTKEYPATH="/path/to/your-input-key.pem" \ --CERTIMATE_DEPLOYER_TENCENTCLOUDVOD_SECRETID="your-secret-id" \ --CERTIMATE_DEPLOYER_TENCENTCLOUDVOD_SECRETKEY="your-secret-key" \ - --CERTIMATE_DEPLOYER_TENCENTCLOUDVOD_REGION="ap-guangzhou" \ --CERTIMATE_DEPLOYER_TENCENTCLOUDVOD_SUBAPPID="your-app-id" \ --CERTIMATE_DEPLOYER_TENCENTCLOUDVOD_DOMAIN="example.com" */ @@ -57,7 +54,6 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath), fmt.Sprintf("SECRETID: %v", fSecretId), fmt.Sprintf("SECRETKEY: %v", fSecretKey), - fmt.Sprintf("REGION: %v", fRegion), fmt.Sprintf("DOMAIN: %v", fDomain), fmt.Sprintf("INSTANCEID: %v", fInstanceId), }, "\n")) @@ -65,7 +61,6 @@ func TestDeploy(t *testing.T) { deployer, err := provider.NewDeployer(&provider.DeployerConfig{ SecretId: fSecretId, SecretKey: fSecretKey, - Region: fRegion, SubAppId: fSubAppId, Domain: fDomain, }) diff --git a/internal/pkg/core/deployer/providers/tencentcloud-waf/tencentcloud_waf.go b/internal/pkg/core/deployer/providers/tencentcloud-waf/tencentcloud_waf.go index 7919516c..c84067ce 100644 --- a/internal/pkg/core/deployer/providers/tencentcloud-waf/tencentcloud_waf.go +++ b/internal/pkg/core/deployer/providers/tencentcloud-waf/tencentcloud_waf.go @@ -46,7 +46,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { client, err := createSdkClient(config.SecretId, config.SecretKey, config.Region) if err != nil { - return nil, xerrors.Wrap(err, "failed to create sdk clients") + return nil, xerrors.Wrap(err, "failed to create sdk client") } uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ diff --git a/internal/pkg/core/deployer/providers/webhook/webhook.go b/internal/pkg/core/deployer/providers/webhook/webhook.go index 7a9edfda..6a1e8a21 100644 --- a/internal/pkg/core/deployer/providers/webhook/webhook.go +++ b/internal/pkg/core/deployer/providers/webhook/webhook.go @@ -2,6 +2,7 @@ package webhook import ( "context" + "crypto/tls" "encoding/json" "strings" "time" @@ -19,6 +20,8 @@ type DeployerConfig struct { WebhookUrl string `json:"webhookUrl"` // Webhook 回调数据(JSON 格式)。 WebhookData string `json:"webhookData,omitempty"` + // 是否允许不安全的连接。 + AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` } type DeployerProvider struct { @@ -38,6 +41,9 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { SetTimeout(30 * time.Second). SetRetryCount(3). SetRetryWaitTime(5 * time.Second) + if config.AllowInsecureConnections { + client.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}) + } return &DeployerProvider{ config: config, diff --git a/internal/pkg/core/deployer/providers/webhook/webhook_test.go b/internal/pkg/core/deployer/providers/webhook/webhook_test.go index 7dd6f24a..a31ef913 100644 --- a/internal/pkg/core/deployer/providers/webhook/webhook_test.go +++ b/internal/pkg/core/deployer/providers/webhook/webhook_test.go @@ -49,8 +49,9 @@ func TestDeploy(t *testing.T) { }, "\n")) deployer, err := provider.NewDeployer(&provider.DeployerConfig{ - WebhookUrl: fWebhookUrl, - WebhookData: fWebhookData, + WebhookUrl: fWebhookUrl, + WebhookData: fWebhookData, + AllowInsecureConnections: true, }) if err != nil { t.Errorf("err: %+v", err) diff --git a/internal/pkg/core/notifier/providers/webhook/webhook.go b/internal/pkg/core/notifier/providers/webhook/webhook.go index 55c0e668..f753645a 100644 --- a/internal/pkg/core/notifier/providers/webhook/webhook.go +++ b/internal/pkg/core/notifier/providers/webhook/webhook.go @@ -2,8 +2,10 @@ import ( "context" + "crypto/tls" + "net/http" - "github.com/nikoksr/notify/service/http" + webhook "github.com/nikoksr/notify/service/http" "github.com/usual2970/certimate/internal/pkg/core/notifier" ) @@ -11,6 +13,8 @@ import ( type NotifierConfig struct { // Webhook URL。 Url string `json:"url"` + // 是否允许不安全的连接。 + AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` } type NotifierProvider struct { @@ -30,10 +34,16 @@ func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) { } func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { - srv := http.New() - + srv := webhook.New() srv.AddReceiversURLs(n.config.Url) + if n.config.AllowInsecureConnections { + tlsConfig := &tls.Config{InsecureSkipVerify: true} + transport := &http.Transport{TLSClientConfig: tlsConfig} + client := &http.Client{Transport: transport} + srv.WithClient(client) + } + err = srv.Send(ctx, subject, message) if err != nil { return nil, err diff --git a/internal/pkg/core/notifier/providers/webhook/webhook_test.go b/internal/pkg/core/notifier/providers/webhook/webhook_test.go index 7afe6be4..8210358b 100644 --- a/internal/pkg/core/notifier/providers/webhook/webhook_test.go +++ b/internal/pkg/core/notifier/providers/webhook/webhook_test.go @@ -39,7 +39,8 @@ func TestNotify(t *testing.T) { }, "\n")) notifier, err := provider.NewNotifier(&provider.NotifierConfig{ - Url: fUrl, + Url: fUrl, + AllowInsecureConnections: true, }) if err != nil { t.Errorf("err: %+v", err) diff --git a/internal/pkg/core/uploader/providers/1panel-ssl/1panel_ssl.go b/internal/pkg/core/uploader/providers/1panel-ssl/1panel_ssl.go new file mode 100644 index 00000000..bb612bec --- /dev/null +++ b/internal/pkg/core/uploader/providers/1panel-ssl/1panel_ssl.go @@ -0,0 +1,125 @@ +package onepanelssl + +import ( + "context" + "errors" + "fmt" + "net/url" + "strings" + "time" + + xerrors "github.com/pkg/errors" + + "github.com/usual2970/certimate/internal/pkg/core/uploader" + opsdk "github.com/usual2970/certimate/internal/pkg/vendors/1panel-sdk" +) + +type UploaderConfig struct { + // 1Panel 地址。 + ApiUrl string `json:"apiUrl"` + // 1Panel 接口密钥。 + ApiKey string `json:"apiKey"` +} + +type UploaderProvider struct { + config *UploaderConfig + sdkClient *opsdk.Client +} + +var _ uploader.Uploader = (*UploaderProvider)(nil) + +func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { + if config == nil { + panic("config is nil") + } + + client, err := createSdkClient(config.ApiUrl, config.ApiKey) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk client") + } + + return &UploaderProvider{ + config: config, + sdkClient: client, + }, nil +} + +func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { + // 遍历证书列表,避免重复上传 + if res, err := u.getExistCert(ctx, certPem, privkeyPem); err != nil { + return nil, err + } else if res != nil { + return res, nil + } + + // 生成新证书名(需符合 1Panel 命名规则) + certName := fmt.Sprintf("certimate-%d", time.Now().UnixMilli()) + + // 上传证书 + uploadWebsiteSSLReq := &opsdk.UploadWebsiteSSLRequest{ + Type: "paste", + Description: certName, + Certificate: certPem, + PrivateKey: privkeyPem, + } + uploadWebsiteSSLResp, err := u.sdkClient.UploadWebsiteSSL(uploadWebsiteSSLReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request '1panel.UploadWebsiteSSL'") + } + + // 遍历证书列表,获取刚刚上传证书 ID + if res, err := u.getExistCert(ctx, certPem, privkeyPem); err != nil { + return nil, err + } else if res == nil { + return nil, fmt.Errorf("no ssl certificate found, may be upload failed (code: %d, message: %s)", uploadWebsiteSSLResp.GetCode(), uploadWebsiteSSLResp.GetMessage()) + } else { + return res, nil + } +} + +func (u *UploaderProvider) getExistCert(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { + searchWebsiteSSLPageNumber := int32(1) + searchWebsiteSSLPageSize := int32(100) + for { + searchWebsiteSSLReq := &opsdk.SearchWebsiteSSLRequest{ + Page: searchWebsiteSSLPageNumber, + PageSize: searchWebsiteSSLPageSize, + } + searchWebsiteSSLResp, err := u.sdkClient.SearchWebsiteSSL(searchWebsiteSSLReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request '1panel.SearchWebsiteSSL'") + } + + for _, sslItem := range searchWebsiteSSLResp.Data.Items { + if strings.TrimSpace(sslItem.PEM) == strings.TrimSpace(certPem) && + strings.TrimSpace(sslItem.PrivateKey) == strings.TrimSpace(privkeyPem) { + // 如果已存在相同证书,直接返回已有的证书信息 + return &uploader.UploadResult{ + CertId: fmt.Sprintf("%d", sslItem.ID), + CertName: sslItem.Description, + }, nil + } + } + + if len(searchWebsiteSSLResp.Data.Items) < int(searchWebsiteSSLPageSize) { + break + } else { + searchWebsiteSSLPageNumber++ + } + } + + return nil, nil +} + +func createSdkClient(apiUrl, apiKey string) (*opsdk.Client, error) { + if _, err := url.Parse(apiUrl); err != nil { + return nil, errors.New("invalid 1panel api url") + } + + if apiKey == "" { + return nil, errors.New("invalid 1panel api key") + } + + client := opsdk.NewClient(apiUrl, apiKey) + return client, nil +} diff --git a/internal/pkg/core/uploader/providers/1panel-ssl/1panel_ssl_test.go b/internal/pkg/core/uploader/providers/1panel-ssl/1panel_ssl_test.go new file mode 100644 index 00000000..5f146dd1 --- /dev/null +++ b/internal/pkg/core/uploader/providers/1panel-ssl/1panel_ssl_test.go @@ -0,0 +1,72 @@ +package onepanelssl_test + +import ( + "context" + "encoding/json" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/1panel-ssl" +) + +var ( + fInputCertPath string + fInputKeyPath string + fApiUrl string + fApiKey string +) + +func init() { + argsPrefix := "CERTIMATE_UPLOADER_1PANELSSL_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "") + flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "") +} + +/* +Shell command to run this test: + + go test -v ./1panel_ssl_test.go -args \ + --CERTIMATE_UPLOADER_1PANELSSL_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_UPLOADER_1PANELSSL_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_UPLOADER_1PANELSSL_APIURL="http://127.0.0.1:20410" \ + --CERTIMATE_UPLOADER_1PANELSSL_APIKEY="your-api-key" +*/ +func TestDeploy(t *testing.T) { + flag.Parse() + + t.Run("Deploy", func(t *testing.T) { + t.Log(strings.Join([]string{ + "args:", + fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath), + fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath), + fmt.Sprintf("APIURL: %v", fApiUrl), + fmt.Sprintf("APIKEY: %v", fApiKey), + }, "\n")) + + uploader, err := provider.NewUploader(&provider.UploaderConfig{ + ApiUrl: fApiUrl, + ApiKey: fApiKey, + }) + if err != nil { + t.Errorf("err: %+v", err) + return + } + + fInputCertData, _ := os.ReadFile(fInputCertPath) + fInputKeyData, _ := os.ReadFile(fInputKeyPath) + res, err := uploader.Upload(context.Background(), string(fInputCertData), string(fInputKeyData)) + if err != nil { + t.Errorf("err: %+v", err) + return + } + + sres, _ := json.Marshal(res) + t.Logf("ok: %s", string(sres)) + }) +} diff --git a/internal/pkg/core/uploader/providers/aliyun-cas/aliyun_cas.go b/internal/pkg/core/uploader/providers/aliyun-cas/aliyun_cas.go index 202339c4..2b582409 100644 --- a/internal/pkg/core/uploader/providers/aliyun-cas/aliyun_cas.go +++ b/internal/pkg/core/uploader/providers/aliyun-cas/aliyun_cas.go @@ -143,7 +143,7 @@ func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunCas.Cl region = "cn-hangzhou" // CAS 服务默认区域:华东一杭州 } - // 接入点一览 https://help.aliyun.com/zh/ssl-certificate/developer-reference/endpoints + // 接入点一览 https://api.aliyun.com/product/cas var endpoint string switch region { case "cn-hangzhou": diff --git a/internal/pkg/core/uploader/providers/aliyun-slb/aliyun_slb.go b/internal/pkg/core/uploader/providers/aliyun-slb/aliyun_slb.go index c53eced2..d687822a 100644 --- a/internal/pkg/core/uploader/providers/aliyun-slb/aliyun_slb.go +++ b/internal/pkg/core/uploader/providers/aliyun-slb/aliyun_slb.go @@ -119,7 +119,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe } func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunSlb.Client, error) { - // 接入点一览 https://help.aliyun.com/zh/slb/classic-load-balancer/developer-reference/api-slb-2014-05-15-endpoint + // 接入点一览 https://api.aliyun.com/product/Slb var endpoint string switch region { case diff --git a/internal/pkg/core/uploader/providers/ucloud-ussl/ucloud_ussl.go b/internal/pkg/core/uploader/providers/ucloud-ussl/ucloud_ussl.go index e5d2fc1c..67506bf4 100644 --- a/internal/pkg/core/uploader/providers/ucloud-ussl/ucloud_ussl.go +++ b/internal/pkg/core/uploader/providers/ucloud-ussl/ucloud_ussl.go @@ -76,7 +76,13 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe uploadNormalCertificateResp, err := u.sdkClient.UploadNormalCertificate(uploadNormalCertificateReq) if err != nil { if uploadNormalCertificateResp != nil && uploadNormalCertificateResp.GetRetCode() == 80035 { - return u.getExistCert(ctx, certPem) + if res, err := u.getExistCert(ctx, certPem); err != nil { + return nil, err + } else if res == nil { + return nil, errors.New("no certificate found") + } else { + return res, nil + } } return nil, xerrors.Wrap(err, "failed to execute sdk request 'ussl.UploadNormalCertificate'") @@ -205,7 +211,7 @@ func (u *UploaderProvider) getExistCert(ctx context.Context, certPem string) (re } } - return nil, errors.New("no certificate found") + return nil, nil } func createSdkClient(privateKey, publicKey string) (*usdkSsl.USSLClient, error) { diff --git a/internal/pkg/vendors/1panel-sdk/api.go b/internal/pkg/vendors/1panel-sdk/api.go new file mode 100644 index 00000000..a6390408 --- /dev/null +++ b/internal/pkg/vendors/1panel-sdk/api.go @@ -0,0 +1,51 @@ +package onepanelsdk + +import ( + "fmt" + "net/http" +) + +func (c *Client) UpdateSystemSSL(req *UpdateSystemSSLRequest) (*UpdateSystemSSLResponse, error) { + resp := &UpdateSystemSSLResponse{} + err := c.sendRequestWithResult(http.MethodPost, "/settings/ssl/update", req, resp) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *Client) SearchWebsiteSSL(req *SearchWebsiteSSLRequest) (*SearchWebsiteSSLResponse, error) { + resp := &SearchWebsiteSSLResponse{} + err := c.sendRequestWithResult(http.MethodPost, "/websites/ssl/search", req, resp) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *Client) UploadWebsiteSSL(req *UploadWebsiteSSLRequest) (*UploadWebsiteSSLResponse, error) { + resp := &UploadWebsiteSSLResponse{} + err := c.sendRequestWithResult(http.MethodPost, "/websites/ssl/upload", req, resp) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *Client) GetHttpsConf(req *GetHttpsConfRequest) (*GetHttpsConfResponse, error) { + resp := &GetHttpsConfResponse{} + err := c.sendRequestWithResult(http.MethodGet, fmt.Sprintf("/websites/%d/https", req.WebsiteID), req, resp) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *Client) UpdateHttpsConf(req *UpdateHttpsConfRequest) (*UpdateHttpsConfResponse, error) { + resp := &UpdateHttpsConfResponse{} + err := c.sendRequestWithResult(http.MethodPost, fmt.Sprintf("/websites/%d/https", req.WebsiteID), req, resp) + if err != nil { + return nil, err + } + return resp, nil +} diff --git a/internal/pkg/vendors/1panel-sdk/client.go b/internal/pkg/vendors/1panel-sdk/client.go new file mode 100644 index 00000000..9c424111 --- /dev/null +++ b/internal/pkg/vendors/1panel-sdk/client.go @@ -0,0 +1,101 @@ +package onepanelsdk + +import ( + "crypto/md5" + "crypto/tls" + "encoding/hex" + "encoding/json" + "fmt" + "net/http" + "strings" + "time" + + "github.com/go-resty/resty/v2" +) + +type Client struct { + apiHost string + apiKey string + + client *resty.Client +} + +func NewClient(apiHost, apiKey string) *Client { + client := resty.New() + + return &Client{ + apiHost: strings.TrimRight(apiHost, "/"), + apiKey: apiKey, + client: client, + } +} + +func (c *Client) WithTimeout(timeout time.Duration) *Client { + c.client.SetTimeout(timeout) + return c +} + +func (c *Client) WithTLSConfig(config *tls.Config) *Client { + c.client.SetTLSClientConfig(config) + return c +} + +func (c *Client) generateToken(timestamp string) string { + tokenMd5 := md5.Sum([]byte("1panel" + c.apiKey + timestamp)) + tokenMd5Hex := hex.EncodeToString(tokenMd5[:]) + return tokenMd5Hex +} + +func (c *Client) sendRequest(method string, path string, params interface{}) (*resty.Response, error) { + req := c.client.R() + req.Method = method + req.URL = c.apiHost + "/api/v1" + path + if strings.EqualFold(method, http.MethodGet) { + qs := make(map[string]string) + if params != nil { + temp := make(map[string]any) + jsonb, _ := json.Marshal(params) + json.Unmarshal(jsonb, &temp) + for k, v := range temp { + if v != nil { + qs[k] = fmt.Sprintf("%v", v) + } + } + } + + req = req.SetQueryParams(qs) + } else { + req = req. + SetHeader("Content-Type", "application/json"). + SetBody(params) + } + + timestamp := fmt.Sprintf("%d", time.Now().Unix()) + token := c.generateToken(timestamp) + req.SetHeader("1Panel-Timestamp", timestamp) + req.SetHeader("1Panel-Token", token) + + resp, err := req.Send() + if err != nil { + return nil, fmt.Errorf("1panel api error: failed to send request: %w", err) + } else if resp.IsError() { + return nil, fmt.Errorf("1panel api error: unexpected status code: %d, %s", resp.StatusCode(), resp.Body()) + } + + return resp, nil +} + +func (c *Client) sendRequestWithResult(method string, path string, params interface{}, result BaseResponse) error { + resp, err := c.sendRequest(method, path, params) + if err != nil { + return err + } + + if err := json.Unmarshal(resp.Body(), &result); err != nil { + return fmt.Errorf("1panel api error: failed to parse response: %w", err) + } else if errcode := result.GetCode(); errcode/100 != 2 { + return fmt.Errorf("1panel api error: %d - %s", errcode, result.GetMessage()) + } + + return nil +} diff --git a/internal/pkg/vendors/1panel-sdk/models.go b/internal/pkg/vendors/1panel-sdk/models.go new file mode 100644 index 00000000..8510aefe --- /dev/null +++ b/internal/pkg/vendors/1panel-sdk/models.go @@ -0,0 +1,103 @@ +package onepanelsdk + +type BaseResponse interface { + GetCode() int32 + GetMessage() string +} + +type baseResponse struct { + Code int32 `json:"code"` + Message string `json:"message"` +} + +func (r *baseResponse) GetCode() int32 { + return r.Code +} + +func (r *baseResponse) GetMessage() string { + return r.Message +} + +type UpdateSystemSSLRequest struct { + Cert string `json:"cert"` + Key string `json:"key"` + SSLType string `json:"sslType"` + SSL string `json:"ssl"` + SSLID int64 `json:"sslID"` + AutoRestart string `json:"autoRestart"` +} + +type UpdateSystemSSLResponse struct { + baseResponse +} + +type SearchWebsiteSSLRequest struct { + Page int32 `json:"page"` + PageSize int32 `json:"pageSize"` +} + +type SearchWebsiteSSLResponse struct { + baseResponse + Data struct { + Items []*struct { + ID int64 `json:"id"` + PEM string `json:"pem"` + PrivateKey string `json:"privateKey"` + Domains string `json:"domains"` + Description string `json:"description"` + Status string `json:"status"` + UpdatedAt string `json:"updatedAt"` + CreatedAt string `json:"createdAt"` + } `json:"items"` + Total int32 `json:"total"` + } `json:"data"` +} + +type UploadWebsiteSSLRequest struct { + Type string `json:"type"` + SSLID int64 `json:"sslID"` + Certificate string `json:"certificate"` + CertificatePath string `json:"certificatePath"` + PrivateKey string `json:"privateKey"` + PrivateKeyPath string `json:"privateKeyPath"` + Description string `json:"description"` +} + +type UploadWebsiteSSLResponse struct { + baseResponse +} + +type GetHttpsConfRequest struct { + WebsiteID int64 `json:"-"` +} + +type GetHttpsConfResponse struct { + baseResponse + Data struct { + Enable bool `json:"enable"` + HttpConfig string `json:"httpConfig"` + SSLProtocol []string `json:"SSLProtocol"` + Algorithm string `json:"algorithm"` + Hsts bool `json:"hsts"` + } `json:"data"` +} + +type UpdateHttpsConfRequest struct { + WebsiteID int64 `json:"websiteId"` + Enable bool `json:"enable"` + Type string `json:"type"` + WebsiteSSLID int64 `json:"websiteSSLId"` + PrivateKey string `json:"privateKey"` + Certificate string `json:"certificate"` + PrivateKeyPath string `json:"privateKeyPath"` + CertificatePath string `json:"certificatePath"` + ImportType string `json:"importType"` + HttpConfig string `json:"httpConfig"` + SSLProtocol []string `json:"SSLProtocol"` + Algorithm string `json:"algorithm"` + Hsts bool `json:"hsts"` +} + +type UpdateHttpsConfResponse struct { + baseResponse +} diff --git a/internal/pkg/vendors/btpanel-sdk/client.go b/internal/pkg/vendors/btpanel-sdk/client.go index 54564f0e..847a4387 100644 --- a/internal/pkg/vendors/btpanel-sdk/client.go +++ b/internal/pkg/vendors/btpanel-sdk/client.go @@ -2,6 +2,7 @@ package btpanelsdk import ( "crypto/md5" + "crypto/tls" "encoding/hex" "encoding/json" "fmt" @@ -34,6 +35,11 @@ func (c *Client) WithTimeout(timeout time.Duration) *Client { return c } +func (c *Client) WithTLSConfig(config *tls.Config) *Client { + c.client.SetTLSClientConfig(config) + return c +} + func (c *Client) generateSignature(timestamp string) string { keyMd5 := md5.Sum([]byte(c.apiKey)) keyMd5Hex := strings.ToLower(hex.EncodeToString(keyMd5[:])) diff --git a/internal/pkg/vendors/cmcc-sdk/README.md b/internal/pkg/vendors/cmcc-sdk/README.md index c64eebe8..76f73112 100644 --- a/internal/pkg/vendors/cmcc-sdk/README.md +++ b/internal/pkg/vendors/cmcc-sdk/README.md @@ -8,7 +8,6 @@ 1. 原始包必须通过移动云私有仓库获取, 为构建带来不便。 2. 原始包存在部分内容错误, 需要自行修改, 如: - - 存在一些编译错误; - 返回错误的时候, 未返回错误信息; - 解析响应体错误。 diff --git a/internal/pkg/vendors/safeline-sdk/client.go b/internal/pkg/vendors/safeline-sdk/client.go index c6e6caf1..0d47c028 100644 --- a/internal/pkg/vendors/safeline-sdk/client.go +++ b/internal/pkg/vendors/safeline-sdk/client.go @@ -1,6 +1,7 @@ package safelinesdk import ( + "crypto/tls" "encoding/json" "fmt" "strings" @@ -31,6 +32,11 @@ func (c *Client) WithTimeout(timeout time.Duration) *Client { return c } +func (c *Client) WithTLSConfig(config *tls.Config) *Client { + c.client.SetTLSClientConfig(config) + return c +} + func (c *Client) sendRequest(path string, params interface{}) (*resty.Response, error) { url := c.apiHost + path req := c.client.R(). diff --git a/internal/repository/statistics.go b/internal/repository/statistics.go index 0e139cea..395feb09 100644 --- a/internal/repository/statistics.go +++ b/internal/repository/statistics.go @@ -21,7 +21,7 @@ func (r *StatisticsRepository) Get(ctx context.Context) (*domain.Statistics, err Total int `db:"total"` }{} if err := app.GetDB(). - NewQuery("SELECT COUNT(*) AS total FROM certificate"). + NewQuery("SELECT COUNT(*) AS total FROM certificate WHERE deleted = ''"). One(&certTotal); err != nil { return nil, err } @@ -32,7 +32,7 @@ func (r *StatisticsRepository) Get(ctx context.Context) (*domain.Statistics, err Total int `db:"total"` }{} if err := app.GetDB(). - NewQuery("SELECT COUNT(*) AS total FROM certificate WHERE expireAt > DATETIME('now') and expireAt < DATETIME('now', '+20 days')"). + NewQuery("SELECT COUNT(*) AS total FROM certificate WHERE expireAt > DATETIME('now') and expireAt < DATETIME('now', '+20 days') AND deleted = ''"). One(&certExpireSoonTotal); err != nil { return nil, err } @@ -43,7 +43,7 @@ func (r *StatisticsRepository) Get(ctx context.Context) (*domain.Statistics, err Total int `db:"total"` }{} if err := app.GetDB(). - NewQuery("SELECT COUNT(*) AS total FROM certificate WHERE expireAt < DATETIME('now')"). + NewQuery("SELECT COUNT(*) AS total FROM certificate WHERE expireAt < DATETIME('now') AND deleted = ''"). One(&certExpiredTotal); err != nil { return nil, err } diff --git a/ui/package-lock.json b/ui/package-lock.json index 8a62cdef..2aafc283 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -9,25 +9,25 @@ "version": "0.0.0", "dependencies": { "@ant-design/icons": "^5.6.1", - "@ant-design/pro-components": "^2.8.5", + "@ant-design/pro-components": "^2.8.6", "ahooks": "^3.8.4", - "antd": "^5.24.0", + "antd": "^5.24.3", "antd-zod": "^6.0.1", "clsx": "^2.1.1", - "cron-parser": "^4.9.0", + "cron-parser": "^5.0.4", "file-saver": "^2.0.5", "i18next": "^24.2.2", - "i18next-browser-languagedetector": "^8.0.2", + "i18next-browser-languagedetector": "^8.0.4", "immer": "^10.1.1", - "lucide-react": "^0.475.0", - "nanoid": "^5.0.9", - "pocketbase": "^0.25.1", + "lucide-react": "^0.477.0", + "nanoid": "^5.1.2", + "pocketbase": "^0.25.2", "radash": "^12.1.0", "react": "^18.3.1", "react-copy-to-clipboard": "^5.1.0", "react-dom": "^18.3.1", - "react-i18next": "^15.4.0", - "react-router-dom": "^7.1.5", + "react-i18next": "^15.4.1", + "react-router-dom": "^7.2.0", "tailwind-merge": "^2.6.0", "zod": "^3.24.2", "zustand": "^5.0.3" @@ -35,30 +35,30 @@ "devDependencies": { "@types/file-saver": "^2.0.7", "@types/fs-extra": "^11.0.4", - "@types/node": "^22.10.7", + "@types/node": "^22.13.9", "@types/react": "^18.3.12", "@types/react-copy-to-clipboard": "^5.0.7", "@types/react-dom": "^18.3.1", - "@typescript-eslint/eslint-plugin": "^8.24.0", - "@typescript-eslint/parser": "^8.24.0", - "@vitejs/plugin-legacy": "^6.0.1", + "@typescript-eslint/eslint-plugin": "^8.26.0", + "@typescript-eslint/parser": "^8.26.0", + "@vitejs/plugin-legacy": "^6.0.2", "@vitejs/plugin-react": "^4.3.4", "autoprefixer": "^10.4.20", "eslint": "^8.57.0", - "eslint-config-prettier": "^10.0.1", - "eslint-import-resolver-typescript": "^3.7.0", + "eslint-config-prettier": "^10.0.2", + "eslint-import-resolver-typescript": "^3.8.3", "eslint-plugin-import": "^2.31.0", "eslint-plugin-prettier": "^5.2.3", - "eslint-plugin-react-hooks": "^5.1.0", + "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.19", "eslint-plugin-tailwindcss": "^3.18.0", "fs-extra": "^11.3.0", - "postcss": "^8.5.2", - "prettier": "^3.5.0", + "postcss": "^8.5.3", + "prettier": "^3.5.3", "tailwindcss": "^3.4.17", "tailwindcss-animate": "^1.0.7", - "typescript": "^5.7.3", - "vite": "^6.1.0" + "typescript": "^5.8.2", + "vite": "^6.2.0" } }, "node_modules/@alloc/quick-lru": { @@ -162,14 +162,14 @@ "integrity": "sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==" }, "node_modules/@ant-design/pro-card": { - "version": "2.9.5", - "resolved": "https://registry.npmmirror.com/@ant-design/pro-card/-/pro-card-2.9.5.tgz", - "integrity": "sha512-2ioOI6G4/zkC+YgnvRjAMgKKz2VNuGCaqYrmpDZDCl7ptWiwDoE13uQxR7+5x7STGzMwQLSf09Z45Qh1IUVJiQ==", + "version": "2.9.6", + "resolved": "https://registry.npmmirror.com/@ant-design/pro-card/-/pro-card-2.9.6.tgz", + "integrity": "sha512-boUvowODMhc1l55ZZj/08YwnaggL50fAio2NaA7uXsgpbLduSPL2OE0RyiI24NCqFhPRZMZQHbPOmcHw4Bf3yQ==", "dependencies": { "@ant-design/cssinjs": "^1.21.1", "@ant-design/icons": "^5.0.0", "@ant-design/pro-provider": "2.15.3", - "@ant-design/pro-utils": "2.16.3", + "@ant-design/pro-utils": "2.16.4", "@babel/runtime": "^7.18.0", "classnames": "^2.3.2", "rc-resize-observer": "^1.0.0", @@ -181,20 +181,20 @@ } }, "node_modules/@ant-design/pro-components": { - "version": "2.8.5", - "resolved": "https://registry.npmmirror.com/@ant-design/pro-components/-/pro-components-2.8.5.tgz", - "integrity": "sha512-wHPuoPXN6qVBAE6L6GKGPfMG0dUZWnsGAA9i66jIQYibATOY3ggw9VcBYVUhZKbFa6VlJ5axFMrSvYYgha6HQA==", + "version": "2.8.6", + "resolved": "https://registry.npmmirror.com/@ant-design/pro-components/-/pro-components-2.8.6.tgz", + "integrity": "sha512-iNd9kTLI0vAYGiyVrpDRflmee+h7486OLXIgIb89g3G+5YS9xSnRuCYt6UBRAEGsB1GRUPznRUGUd6Gsg33V+g==", "dependencies": { - "@ant-design/pro-card": "2.9.5", - "@ant-design/pro-descriptions": "2.6.5", - "@ant-design/pro-field": "3.0.2", - "@ant-design/pro-form": "2.31.5", - "@ant-design/pro-layout": "7.22.2", - "@ant-design/pro-list": "2.6.5", + "@ant-design/pro-card": "2.9.6", + "@ant-design/pro-descriptions": "2.6.6", + "@ant-design/pro-field": "3.0.3", + "@ant-design/pro-form": "2.31.6", + "@ant-design/pro-layout": "7.22.3", + "@ant-design/pro-list": "2.6.6", "@ant-design/pro-provider": "2.15.3", "@ant-design/pro-skeleton": "2.2.1", - "@ant-design/pro-table": "3.18.5", - "@ant-design/pro-utils": "2.16.3", + "@ant-design/pro-table": "3.18.6", + "@ant-design/pro-utils": "2.16.4", "@babel/runtime": "^7.16.3" }, "peerDependencies": { @@ -204,15 +204,15 @@ } }, "node_modules/@ant-design/pro-descriptions": { - "version": "2.6.5", - "resolved": "https://registry.npmmirror.com/@ant-design/pro-descriptions/-/pro-descriptions-2.6.5.tgz", - "integrity": "sha512-aj6pUCKpOcwYykSc6zAG8GJf5AJoNf1K8u2QfOB0qKdgK9wGFITUphfM+rFMxa1CrpDGbtApsmOmDLtYlkH2sg==", + "version": "2.6.6", + "resolved": "https://registry.npmmirror.com/@ant-design/pro-descriptions/-/pro-descriptions-2.6.6.tgz", + "integrity": "sha512-Onwn79P5wNcFNHQmXVdTDgewXt4MCW5snEFctZuCY6T5KwpH7Y9UA8GWtFNIL2KfF5+uu83es20N0E2hg73G0w==", "dependencies": { - "@ant-design/pro-field": "3.0.2", - "@ant-design/pro-form": "2.31.5", + "@ant-design/pro-field": "3.0.3", + "@ant-design/pro-form": "2.31.6", "@ant-design/pro-provider": "2.15.3", "@ant-design/pro-skeleton": "2.2.1", - "@ant-design/pro-utils": "2.16.3", + "@ant-design/pro-utils": "2.16.4", "@babel/runtime": "^7.18.0", "rc-resize-observer": "^0.2.3", "rc-util": "^5.0.6" @@ -238,13 +238,13 @@ } }, "node_modules/@ant-design/pro-field": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/@ant-design/pro-field/-/pro-field-3.0.2.tgz", - "integrity": "sha512-eqJxMUeMLfBFs0AXH7geAsmCLEiYrRJw+tmyHO8bioUUgw8O2abG2jwdMRVOMkhhIKszbpLDNYOmCB2h/36eEQ==", + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/@ant-design/pro-field/-/pro-field-3.0.3.tgz", + "integrity": "sha512-MrDZcx1kP4vpmnSJyHuxeool2o5hDRiJ8aRFloM2M7yW+Tw9ilABMlHFkKz1FLIt4esO9Zc4vd8Iv2ndlkB4/Q==", "dependencies": { "@ant-design/icons": "^5.0.0", "@ant-design/pro-provider": "2.15.3", - "@ant-design/pro-utils": "2.16.3", + "@ant-design/pro-utils": "2.16.4", "@babel/runtime": "^7.18.0", "@chenshuai2144/sketch-color": "^1.0.8", "classnames": "^2.3.2", @@ -260,14 +260,14 @@ } }, "node_modules/@ant-design/pro-form": { - "version": "2.31.5", - "resolved": "https://registry.npmmirror.com/@ant-design/pro-form/-/pro-form-2.31.5.tgz", - "integrity": "sha512-LTFx29c2LvO5m1PWsiI9C0VH78/b9fzC4EldD8OH6hy9dcH1bmKZdrVZogQKD1Y8m4yU43kDNzoPbizow6SdKQ==", + "version": "2.31.6", + "resolved": "https://registry.npmmirror.com/@ant-design/pro-form/-/pro-form-2.31.6.tgz", + "integrity": "sha512-pDthX9AjLiryFrtPFY+Ep1z/CfEbhg++K25p7jA6tyl1gVeOIcHVkLTEFMNKmWrc9ZSCA35D/UeSz3bn102GLg==", "dependencies": { "@ant-design/icons": "^5.0.0", - "@ant-design/pro-field": "3.0.2", + "@ant-design/pro-field": "3.0.3", "@ant-design/pro-provider": "2.15.3", - "@ant-design/pro-utils": "2.16.3", + "@ant-design/pro-utils": "2.16.4", "@babel/runtime": "^7.18.0", "@chenshuai2144/sketch-color": "^1.0.7", "@umijs/use-params": "^1.0.9", @@ -286,14 +286,14 @@ } }, "node_modules/@ant-design/pro-layout": { - "version": "7.22.2", - "resolved": "https://registry.npmmirror.com/@ant-design/pro-layout/-/pro-layout-7.22.2.tgz", - "integrity": "sha512-RlXqN+EVnF1Sup84O0IjS/vMMgwFnbBZwvR+GVnmZg/+cIa4/BDTXyhbb1KRwUqzn1ctDzj7JfbWOWqmGMw6yA==", + "version": "7.22.3", + "resolved": "https://registry.npmmirror.com/@ant-design/pro-layout/-/pro-layout-7.22.3.tgz", + "integrity": "sha512-di/EOMDuoMDRjBweqesYyCxEYr2LCmO82y6A4bSwmmJ6ehxN7HGC73Wx4RuBkzDR7kHLTOXt7WxI6875ENT8mg==", "dependencies": { "@ant-design/cssinjs": "^1.21.1", "@ant-design/icons": "^5.0.0", "@ant-design/pro-provider": "2.15.3", - "@ant-design/pro-utils": "2.16.3", + "@ant-design/pro-utils": "2.16.4", "@babel/runtime": "^7.18.0", "@umijs/route-utils": "^4.0.0", "@umijs/use-params": "^1.0.9", @@ -313,16 +313,16 @@ } }, "node_modules/@ant-design/pro-list": { - "version": "2.6.5", - "resolved": "https://registry.npmmirror.com/@ant-design/pro-list/-/pro-list-2.6.5.tgz", - "integrity": "sha512-Mc8bgxaf4Ro3PUtfTAd6BrvHhNhi8Vi1CzHFJVqwBQo11Qly+T9eLCKIaKnFwm4wfatOL8f5ANCANW3Te/YDYQ==", + "version": "2.6.6", + "resolved": "https://registry.npmmirror.com/@ant-design/pro-list/-/pro-list-2.6.6.tgz", + "integrity": "sha512-Yea/KDd3kjOKklz1AHs66JGvtguvPYYFSaZFXW4m4VBjABHoaF6seo7ySW9UUWgwuoegdGtiglvleYv/rQoEcw==", "dependencies": { "@ant-design/cssinjs": "^1.21.1", "@ant-design/icons": "^5.0.0", - "@ant-design/pro-card": "2.9.5", - "@ant-design/pro-field": "3.0.2", - "@ant-design/pro-table": "3.18.5", - "@ant-design/pro-utils": "2.16.3", + "@ant-design/pro-card": "2.9.6", + "@ant-design/pro-field": "3.0.3", + "@ant-design/pro-table": "3.18.6", + "@ant-design/pro-utils": "2.16.4", "@babel/runtime": "^7.18.0", "classnames": "^2.3.2", "dayjs": "^1.11.10", @@ -384,17 +384,17 @@ } }, "node_modules/@ant-design/pro-table": { - "version": "3.18.5", - "resolved": "https://registry.npmmirror.com/@ant-design/pro-table/-/pro-table-3.18.5.tgz", - "integrity": "sha512-LejqPfHnTL8aKIbh8uOY8BcKAP7OZZlD0UwxPU631OYixuEB5J++ayhZh6Yj3Yye62t3A7lXN9+Tc8pab9Golw==", + "version": "3.18.6", + "resolved": "https://registry.npmmirror.com/@ant-design/pro-table/-/pro-table-3.18.6.tgz", + "integrity": "sha512-ABXavpJWUOGGcer/WLBpRtzWCbfwZX3T8vAwMbLUQAl1xz3TTgkYzDDTcIdwUmtVdkgJUdWc8GdHWangWW30iQ==", "dependencies": { "@ant-design/cssinjs": "^1.21.1", "@ant-design/icons": "^5.0.0", - "@ant-design/pro-card": "2.9.5", - "@ant-design/pro-field": "3.0.2", - "@ant-design/pro-form": "2.31.5", + "@ant-design/pro-card": "2.9.6", + "@ant-design/pro-field": "3.0.3", + "@ant-design/pro-form": "2.31.6", "@ant-design/pro-provider": "2.15.3", - "@ant-design/pro-utils": "2.16.3", + "@ant-design/pro-utils": "2.16.4", "@babel/runtime": "^7.18.0", "@dnd-kit/core": "^6.0.8", "@dnd-kit/modifiers": "^6.0.1", @@ -415,9 +415,9 @@ } }, "node_modules/@ant-design/pro-utils": { - "version": "2.16.3", - "resolved": "https://registry.npmmirror.com/@ant-design/pro-utils/-/pro-utils-2.16.3.tgz", - "integrity": "sha512-uNjKh51v/SUlCJbWfhg2lRQB/TB0MyNMCQkFZ8mZBQ2rk3Ew47Sly6VssVVWMjIWBLE+g9fOgPg0C1IVeilIXA==", + "version": "2.16.4", + "resolved": "https://registry.npmmirror.com/@ant-design/pro-utils/-/pro-utils-2.16.4.tgz", + "integrity": "sha512-PFxqF0fsUsLj8ORvJSuMgVv9NDHwAxZaglzPN/u3jZX7rWYcrHD04EMJEXooZaSyT6Q4+j7SqXDx6oBsdb9zNw==", "dependencies": { "@ant-design/icons": "^5.0.0", "@ant-design/pro-provider": "2.15.3", @@ -475,22 +475,21 @@ } }, "node_modules/@babel/core": { - "version": "7.26.8", - "resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.26.8.tgz", - "integrity": "sha512-l+lkXCHS6tQEc5oUpK28xBOZ6+HwaH7YwoYQbLFiYb4nS2/l1tKnZEtEWkD0GuiYdvArf9qBS0XlQGXzPMsNqQ==", + "version": "7.26.9", + "resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.26.9.tgz", + "integrity": "sha512-lWBYIrF7qK5+GjY5Uy+/hEgp8OJWOD/rpy74GplYRhEauvbHDeFB8t5hPOZxCZ0Oxf4Cc36tK51/l3ymJysrKw==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.8", + "@babel/generator": "^7.26.9", "@babel/helper-compilation-targets": "^7.26.5", "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.7", - "@babel/parser": "^7.26.8", - "@babel/template": "^7.26.8", - "@babel/traverse": "^7.26.8", - "@babel/types": "^7.26.8", - "@types/gensync": "^1.0.0", + "@babel/helpers": "^7.26.9", + "@babel/parser": "^7.26.9", + "@babel/template": "^7.26.9", + "@babel/traverse": "^7.26.9", + "@babel/types": "^7.26.9", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -515,13 +514,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.26.8", - "resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.26.8.tgz", - "integrity": "sha512-ef383X5++iZHWAXX0SXQR6ZyQhw/0KtTkrTz61WXRhFM6dhpHulO/RJz79L8S6ugZHJkOOkUrUdxgdF2YiPFnA==", + "version": "7.26.9", + "resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.26.9.tgz", + "integrity": "sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg==", "dev": true, "dependencies": { - "@babel/parser": "^7.26.8", - "@babel/types": "^7.26.8", + "@babel/parser": "^7.26.9", + "@babel/types": "^7.26.9", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" @@ -568,17 +567,17 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.25.9", - "resolved": "https://registry.npmmirror.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz", - "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==", + "version": "7.26.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.26.9.tgz", + "integrity": "sha512-ubbUqCofvxPRurw5L8WTsCLSkQiVpov4Qx0WMA+jUN+nXBK8ADPlJO1grkFw5CWKC5+sZSOfuGMdX1aI1iT9Sg==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-member-expression-to-functions": "^7.25.9", "@babel/helper-optimise-call-expression": "^7.25.9", - "@babel/helper-replace-supers": "^7.25.9", + "@babel/helper-replace-supers": "^7.26.5", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", - "@babel/traverse": "^7.25.9", + "@babel/traverse": "^7.26.9", "semver": "^6.3.1" }, "engines": { @@ -792,25 +791,25 @@ } }, "node_modules/@babel/helpers": { - "version": "7.26.7", - "resolved": "https://registry.npmmirror.com/@babel/helpers/-/helpers-7.26.7.tgz", - "integrity": "sha512-8NHiL98vsi0mbPQmYAGWwfcFaOy4j2HY49fXJCfuDcdE7fMIsH9a7GdaeXpIBsbT7307WU8KCMp5pUVDNL4f9A==", + "version": "7.26.9", + "resolved": "https://registry.npmmirror.com/@babel/helpers/-/helpers-7.26.9.tgz", + "integrity": "sha512-Mz/4+y8udxBKdmzt/UjPACs4G3j5SshJJEFFKxlCGPydG4JAHXxjWjAwjd09tf6oINvl1VfMJo+nB7H2YKQ0dA==", "dev": true, "dependencies": { - "@babel/template": "^7.25.9", - "@babel/types": "^7.26.7" + "@babel/template": "^7.26.9", + "@babel/types": "^7.26.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.26.8", - "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.26.8.tgz", - "integrity": "sha512-TZIQ25pkSoaKEYYaHbbxkfL36GNsQ6iFiBbeuzAkLnXayKR1yP1zFe+NxuZWWsUyvt8icPU9CCq0sgWGXR1GEw==", + "version": "7.26.9", + "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.26.9.tgz", + "integrity": "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==", "dev": true, "dependencies": { - "@babel/types": "^7.26.8" + "@babel/types": "^7.26.9" }, "bin": { "parser": "bin/babel-parser.js" @@ -1211,12 +1210,12 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.25.9", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz", - "integrity": "sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==", + "version": "7.26.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.26.9.tgz", + "integrity": "sha512-Hry8AusVm8LW5BVFgiyUReuoGzPUpdHQQqJY5bZnbbf+ngOHWuCuYFKw/BqaaWlvEUrF91HMhDtEaI1hZzNbLg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-plugin-utils": "^7.26.5", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { @@ -1774,9 +1773,9 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.26.8", - "resolved": "https://registry.npmmirror.com/@babel/preset-env/-/preset-env-7.26.8.tgz", - "integrity": "sha512-um7Sy+2THd697S4zJEfv/U5MHGJzkN2xhtsR3T/SWRbVSic62nbISh51VVfU9JiO/L/Z97QczHTaFVkOU8IzNg==", + "version": "7.26.9", + "resolved": "https://registry.npmmirror.com/@babel/preset-env/-/preset-env-7.26.9.tgz", + "integrity": "sha512-vX3qPGE8sEKEAZCWk05k3cpTAE3/nOYca++JA+Rd0z2NCNzabmYvEiSShKzm10zdquOIAVXsy2Ei/DTW34KlKQ==", "dev": true, "dependencies": { "@babel/compat-data": "^7.26.8", @@ -1808,7 +1807,7 @@ "@babel/plugin-transform-dynamic-import": "^7.25.9", "@babel/plugin-transform-exponentiation-operator": "^7.26.3", "@babel/plugin-transform-export-namespace-from": "^7.25.9", - "@babel/plugin-transform-for-of": "^7.25.9", + "@babel/plugin-transform-for-of": "^7.26.9", "@babel/plugin-transform-function-name": "^7.25.9", "@babel/plugin-transform-json-strings": "^7.25.9", "@babel/plugin-transform-literals": "^7.25.9", @@ -1891,30 +1890,30 @@ } }, "node_modules/@babel/template": { - "version": "7.26.8", - "resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.26.8.tgz", - "integrity": "sha512-iNKaX3ZebKIsCvJ+0jd6embf+Aulaa3vNBqZ41kM7iTWjx5qzWKXGHiJUW3+nTpQ18SG11hdF8OAzKrpXkb96Q==", + "version": "7.26.9", + "resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.26.9.tgz", + "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==", "dev": true, "dependencies": { "@babel/code-frame": "^7.26.2", - "@babel/parser": "^7.26.8", - "@babel/types": "^7.26.8" + "@babel/parser": "^7.26.9", + "@babel/types": "^7.26.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.26.8", - "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.26.8.tgz", - "integrity": "sha512-nic9tRkjYH0oB2dzr/JoGIm+4Q6SuYeLEiIiZDwBscRMYFJ+tMAz98fuel9ZnbXViA2I0HVSSRRK8DW5fjXStA==", + "version": "7.26.9", + "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.26.9.tgz", + "integrity": "sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg==", "dev": true, "dependencies": { "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.8", - "@babel/parser": "^7.26.8", - "@babel/template": "^7.26.8", - "@babel/types": "^7.26.8", + "@babel/generator": "^7.26.9", + "@babel/parser": "^7.26.9", + "@babel/template": "^7.26.9", + "@babel/types": "^7.26.9", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -1923,9 +1922,9 @@ } }, "node_modules/@babel/types": { - "version": "7.26.8", - "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.26.8.tgz", - "integrity": "sha512-eUuWapzEGWFEpHFxgEaBG8e3n6S8L3MSu0oda755rOfabWPnh0Our1AozNFVUxGFIhbKgd1ksprsoDGMinTOTA==", + "version": "7.26.9", + "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.26.9.tgz", + "integrity": "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.25.9", @@ -2028,9 +2027,9 @@ "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", - "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz", + "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==", "cpu": [ "ppc64" ], @@ -2044,9 +2043,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.24.2.tgz", - "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.25.0.tgz", + "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==", "cpu": [ "arm" ], @@ -2060,9 +2059,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", - "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz", + "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==", "cpu": [ "arm64" ], @@ -2076,9 +2075,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.24.2.tgz", - "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.25.0.tgz", + "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==", "cpu": [ "x64" ], @@ -2092,9 +2091,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", - "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==", + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz", + "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==", "cpu": [ "arm64" ], @@ -2108,9 +2107,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", - "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz", + "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==", "cpu": [ "x64" ], @@ -2124,9 +2123,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", - "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz", + "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==", "cpu": [ "arm64" ], @@ -2140,9 +2139,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", - "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz", + "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==", "cpu": [ "x64" ], @@ -2156,9 +2155,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", - "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz", + "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==", "cpu": [ "arm" ], @@ -2172,9 +2171,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", - "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz", + "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==", "cpu": [ "arm64" ], @@ -2188,9 +2187,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", - "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz", + "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==", "cpu": [ "ia32" ], @@ -2204,9 +2203,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", - "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz", + "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==", "cpu": [ "loong64" ], @@ -2220,9 +2219,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", - "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz", + "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==", "cpu": [ "mips64el" ], @@ -2236,9 +2235,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", - "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz", + "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==", "cpu": [ "ppc64" ], @@ -2252,9 +2251,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", - "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz", + "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==", "cpu": [ "riscv64" ], @@ -2268,9 +2267,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", - "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz", + "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==", "cpu": [ "s390x" ], @@ -2284,9 +2283,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", - "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz", + "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==", "cpu": [ "x64" ], @@ -2300,9 +2299,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", - "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz", + "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==", "cpu": [ "arm64" ], @@ -2316,9 +2315,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", - "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz", + "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==", "cpu": [ "x64" ], @@ -2332,9 +2331,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", - "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz", + "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==", "cpu": [ "arm64" ], @@ -2348,9 +2347,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", - "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz", + "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==", "cpu": [ "x64" ], @@ -2364,9 +2363,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", - "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz", + "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==", "cpu": [ "x64" ], @@ -2380,9 +2379,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", - "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz", + "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==", "cpu": [ "arm64" ], @@ -2396,9 +2395,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", - "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz", + "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==", "cpu": [ "ia32" ], @@ -2412,9 +2411,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", - "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz", + "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==", "cpu": [ "x64" ], @@ -3203,12 +3202,6 @@ "@types/node": "*" } }, - "node_modules/@types/gensync": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/@types/gensync/-/gensync-1.0.4.tgz", - "integrity": "sha512-C3YYeRQWp2fmq9OryX+FoDy8nXS6scQ7dPptD8LnFDAUNcKWJjXQKDNJD3HVm+kOUsXhTOkpi69vI4EuAr95bA==", - "dev": true - }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmmirror.com/@types/json5/-/json5-0.0.29.tgz", @@ -3225,9 +3218,9 @@ } }, "node_modules/@types/node": { - "version": "22.10.7", - "resolved": "https://registry.npmmirror.com/@types/node/-/node-22.10.7.tgz", - "integrity": "sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg==", + "version": "22.13.9", + "resolved": "https://registry.npmmirror.com/@types/node/-/node-22.13.9.tgz", + "integrity": "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw==", "dev": true, "dependencies": { "undici-types": "~6.20.0" @@ -3268,16 +3261,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.24.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.24.0.tgz", - "integrity": "sha512-aFcXEJJCI4gUdXgoo/j9udUYIHgF23MFkg09LFz2dzEmU0+1Plk4rQWv/IYKvPHAtlkkGoB3m5e6oUp+JPsNaQ==", + "version": "8.26.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.26.0.tgz", + "integrity": "sha512-cLr1J6pe56zjKYajK6SSSre6nl1Gj6xDp1TY0trpgPzjVbgDwd09v2Ws37LABxzkicmUjhEeg/fAUjPJJB1v5Q==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.24.0", - "@typescript-eslint/type-utils": "8.24.0", - "@typescript-eslint/utils": "8.24.0", - "@typescript-eslint/visitor-keys": "8.24.0", + "@typescript-eslint/scope-manager": "8.26.0", + "@typescript-eslint/type-utils": "8.26.0", + "@typescript-eslint/utils": "8.26.0", + "@typescript-eslint/visitor-keys": "8.26.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -3293,19 +3286,19 @@ "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.24.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-8.24.0.tgz", - "integrity": "sha512-MFDaO9CYiard9j9VepMNa9MTcqVvSny2N4hkY6roquzj8pdCBRENhErrteaQuu7Yjn1ppk0v1/ZF9CG3KIlrTA==", + "version": "8.26.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-8.26.0.tgz", + "integrity": "sha512-mNtXP9LTVBy14ZF3o7JG69gRPBK/2QWtQd0j0oH26HcY/foyJJau6pNUez7QrM5UHnSvwlQcJXKsk0I99B9pOA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.24.0", - "@typescript-eslint/types": "8.24.0", - "@typescript-eslint/typescript-estree": "8.24.0", - "@typescript-eslint/visitor-keys": "8.24.0", + "@typescript-eslint/scope-manager": "8.26.0", + "@typescript-eslint/types": "8.26.0", + "@typescript-eslint/typescript-estree": "8.26.0", + "@typescript-eslint/visitor-keys": "8.26.0", "debug": "^4.3.4" }, "engines": { @@ -3317,17 +3310,17 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.24.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-8.24.0.tgz", - "integrity": "sha512-HZIX0UByphEtdVBKaQBgTDdn9z16l4aTUz8e8zPQnyxwHBtf5vtl1L+OhH+m1FGV9DrRmoDuYKqzVrvWDcDozw==", + "version": "8.26.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-8.26.0.tgz", + "integrity": "sha512-E0ntLvsfPqnPwng8b8y4OGuzh/iIOm2z8U3S9zic2TeMLW61u5IH2Q1wu0oSTkfrSzwbDJIB/Lm8O3//8BWMPA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.24.0", - "@typescript-eslint/visitor-keys": "8.24.0" + "@typescript-eslint/types": "8.26.0", + "@typescript-eslint/visitor-keys": "8.26.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3338,13 +3331,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.24.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-8.24.0.tgz", - "integrity": "sha512-8fitJudrnY8aq0F1wMiPM1UUgiXQRJ5i8tFjq9kGfRajU+dbPyOuHbl0qRopLEidy0MwqgTHDt6CnSeXanNIwA==", + "version": "8.26.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-8.26.0.tgz", + "integrity": "sha512-ruk0RNChLKz3zKGn2LwXuVoeBcUMh+jaqzN461uMMdxy5H9epZqIBtYj7UiPXRuOpaALXGbmRuZQhmwHhaS04Q==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "8.24.0", - "@typescript-eslint/utils": "8.24.0", + "@typescript-eslint/typescript-estree": "8.26.0", + "@typescript-eslint/utils": "8.26.0", "debug": "^4.3.4", "ts-api-utils": "^2.0.1" }, @@ -3357,13 +3350,13 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.24.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/types/-/types-8.24.0.tgz", - "integrity": "sha512-VacJCBTyje7HGAw7xp11q439A+zeGG0p0/p2zsZwpnMzjPB5WteaWqt4g2iysgGFafrqvyLWqq6ZPZAOCoefCw==", + "version": "8.26.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/types/-/types-8.26.0.tgz", + "integrity": "sha512-89B1eP3tnpr9A8L6PZlSjBvnJhWXtYfZhECqlBl1D9Lme9mHO6iWlsprBtVenQvY1HMhax1mWOjhtL3fh/u+pA==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3374,13 +3367,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.24.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.24.0.tgz", - "integrity": "sha512-ITjYcP0+8kbsvT9bysygfIfb+hBj6koDsu37JZG7xrCiy3fPJyNmfVtaGsgTUSEuTzcvME5YI5uyL5LD1EV5ZQ==", + "version": "8.26.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.26.0.tgz", + "integrity": "sha512-tiJ1Hvy/V/oMVRTbEOIeemA2XoylimlDQ03CgPPNaHYZbpsc78Hmngnt+WXZfJX1pjQ711V7g0H7cSJThGYfPQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.24.0", - "@typescript-eslint/visitor-keys": "8.24.0", + "@typescript-eslint/types": "8.26.0", + "@typescript-eslint/visitor-keys": "8.26.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -3396,19 +3389,19 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/utils": { - "version": "8.24.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-8.24.0.tgz", - "integrity": "sha512-07rLuUBElvvEb1ICnafYWr4hk8/U7X9RDCOqd9JcAMtjh/9oRmcfN4yGzbPVirgMR0+HLVHehmu19CWeh7fsmQ==", + "version": "8.26.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-8.26.0.tgz", + "integrity": "sha512-2L2tU3FVwhvU14LndnQCA2frYC8JnPDVKyQtWFPf8IYFMt/ykEN1bPolNhNbCVgOmdzTlWdusCTKA/9nKrf8Ig==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.24.0", - "@typescript-eslint/types": "8.24.0", - "@typescript-eslint/typescript-estree": "8.24.0" + "@typescript-eslint/scope-manager": "8.26.0", + "@typescript-eslint/types": "8.26.0", + "@typescript-eslint/typescript-estree": "8.26.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3419,16 +3412,16 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.24.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.24.0.tgz", - "integrity": "sha512-kArLq83QxGLbuHrTMoOEWO+l2MwsNS2TGISEdx8xgqpkbytB07XmlQyQdNDrCc1ecSqx0cnmhGvpX+VBwqqSkg==", + "version": "8.26.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.26.0.tgz", + "integrity": "sha512-2z8JQJWAzPdDd51dRQ/oqIJxe99/hoLIqmf8RMCAJQtYDc535W/Jt2+RTP4bP0aKeBG1F65yjIZuczOXCmbWwg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.24.0", + "@typescript-eslint/types": "8.26.0", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -3471,13 +3464,13 @@ "dev": true }, "node_modules/@vitejs/plugin-legacy": { - "version": "6.0.1", - "resolved": "https://registry.npmmirror.com/@vitejs/plugin-legacy/-/plugin-legacy-6.0.1.tgz", - "integrity": "sha512-rMAUn0qXwCemlky7ZmaeP8va5Woz/6yVohDaTu7Wd+Jydi/Z/VmTDBlSOUbYFmfhDaVpV4ppWLiaUOPWqo9H6w==", + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/@vitejs/plugin-legacy/-/plugin-legacy-6.0.2.tgz", + "integrity": "sha512-b/a6ARuJ1yCoIH/lSjpwPMyqo3NSCoqyxYtff7VCC6cnJfvBTzd7PthcrbomhLZnMsp/eW41b6TrbNSQvHW2lA==", "dev": true, "dependencies": { - "@babel/core": "^7.26.7", - "@babel/preset-env": "^7.26.7", + "@babel/core": "^7.26.9", + "@babel/preset-env": "^7.26.9", "browserslist": "^4.24.4", "browserslist-to-esbuild": "^2.1.1", "core-js": "^3.40.0", @@ -3592,9 +3585,9 @@ } }, "node_modules/antd": { - "version": "5.24.0", - "resolved": "https://registry.npmmirror.com/antd/-/antd-5.24.0.tgz", - "integrity": "sha512-05PZBIf6ijLHAQskBTW3nwS2t7tQmyLA6Xq8vK2Sk5tsgCsH/UE1cNCDYnKFGRJ7cKYuWJ565JDo9LejbiO42A==", + "version": "5.24.3", + "resolved": "https://registry.npmmirror.com/antd/-/antd-5.24.3.tgz", + "integrity": "sha512-H5fopyOVRAnegfwLuEdjhPR+l5z3/lo4aQyDsgIYhfmeBcRgN/XNkefVxzRHNuWHeYr9E9LbyxEQcMF91sy5lg==", "dependencies": { "@ant-design/colors": "^7.2.0", "@ant-design/cssinjs": "^1.23.0", @@ -3611,7 +3604,7 @@ "classnames": "^2.5.1", "copy-to-clipboard": "^3.3.3", "dayjs": "^1.11.11", - "rc-cascader": "~3.33.0", + "rc-cascader": "~3.33.1", "rc-checkbox": "~3.5.0", "rc-collapse": "~3.9.0", "rc-dialog": "~9.6.0", @@ -3619,14 +3612,14 @@ "rc-dropdown": "~4.2.1", "rc-field-form": "~2.7.0", "rc-image": "~7.11.0", - "rc-input": "~1.7.2", + "rc-input": "~1.7.3", "rc-input-number": "~9.4.0", "rc-mentions": "~2.19.1", - "rc-menu": "~9.16.0", + "rc-menu": "~9.16.1", "rc-motion": "^2.9.5", "rc-notification": "~5.6.3", "rc-pagination": "~5.1.0", - "rc-picker": "~4.11.0", + "rc-picker": "~4.11.3", "rc-progress": "~4.0.0", "rc-rate": "~2.13.1", "rc-resize-observer": "^1.4.3", @@ -3635,11 +3628,11 @@ "rc-slider": "~11.1.8", "rc-steps": "~6.0.1", "rc-switch": "~4.1.0", - "rc-table": "~7.50.2", + "rc-table": "~7.50.3", "rc-tabs": "~15.5.1", "rc-textarea": "~1.9.0", "rc-tooltip": "~6.4.0", - "rc-tree": "~5.13.0", + "rc-tree": "~5.13.1", "rc-tree-select": "~5.27.0", "rc-upload": "~4.8.1", "rc-util": "^5.44.4", @@ -4195,12 +4188,12 @@ } }, "node_modules/core-js-compat": { - "version": "3.40.0", - "resolved": "https://registry.npmmirror.com/core-js-compat/-/core-js-compat-3.40.0.tgz", - "integrity": "sha512-0XEDpr5y5mijvw8Lbc6E5AkjrHfp7eEoPlu36SWeAbcL8fn1G1ANe8DBlo2XoNN89oVpxWwOjYIPVzR4ZvsKCQ==", + "version": "3.41.0", + "resolved": "https://registry.npmmirror.com/core-js-compat/-/core-js-compat-3.41.0.tgz", + "integrity": "sha512-RFsU9LySVue9RTwdDVX/T0e2Y6jRYWXERKElIjpuEOEnxaXffI0X7RUwVzfYLfzuLXSNJDYoRYUAmRUcyln20A==", "dev": true, "dependencies": { - "browserslist": "^4.24.3" + "browserslist": "^4.24.4" }, "funding": { "type": "opencollective", @@ -4208,14 +4201,14 @@ } }, "node_modules/cron-parser": { - "version": "4.9.0", - "resolved": "https://registry.npmmirror.com/cron-parser/-/cron-parser-4.9.0.tgz", - "integrity": "sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==", + "version": "5.0.4", + "resolved": "https://registry.npmmirror.com/cron-parser/-/cron-parser-5.0.4.tgz", + "integrity": "sha512-ud6L7uGE4a7QxKndq106+99iKMlhG1/gSVlA4SH7qy3xO/R/EUoXFTJFMBOogdk00mZiXPONRI4wFKAcymKp6w==", "dependencies": { - "luxon": "^3.2.1" + "luxon": "^3.5.0" }, "engines": { - "node": ">=12.0.0" + "node": ">=18" } }, "node_modules/cross-spawn": { @@ -4573,9 +4566,9 @@ } }, "node_modules/esbuild": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.24.2.tgz", - "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.25.0.tgz", + "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==", "dev": true, "hasInstallScript": true, "bin": { @@ -4585,31 +4578,31 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.24.2", - "@esbuild/android-arm": "0.24.2", - "@esbuild/android-arm64": "0.24.2", - "@esbuild/android-x64": "0.24.2", - "@esbuild/darwin-arm64": "0.24.2", - "@esbuild/darwin-x64": "0.24.2", - "@esbuild/freebsd-arm64": "0.24.2", - "@esbuild/freebsd-x64": "0.24.2", - "@esbuild/linux-arm": "0.24.2", - "@esbuild/linux-arm64": "0.24.2", - "@esbuild/linux-ia32": "0.24.2", - "@esbuild/linux-loong64": "0.24.2", - "@esbuild/linux-mips64el": "0.24.2", - "@esbuild/linux-ppc64": "0.24.2", - "@esbuild/linux-riscv64": "0.24.2", - "@esbuild/linux-s390x": "0.24.2", - "@esbuild/linux-x64": "0.24.2", - "@esbuild/netbsd-arm64": "0.24.2", - "@esbuild/netbsd-x64": "0.24.2", - "@esbuild/openbsd-arm64": "0.24.2", - "@esbuild/openbsd-x64": "0.24.2", - "@esbuild/sunos-x64": "0.24.2", - "@esbuild/win32-arm64": "0.24.2", - "@esbuild/win32-ia32": "0.24.2", - "@esbuild/win32-x64": "0.24.2" + "@esbuild/aix-ppc64": "0.25.0", + "@esbuild/android-arm": "0.25.0", + "@esbuild/android-arm64": "0.25.0", + "@esbuild/android-x64": "0.25.0", + "@esbuild/darwin-arm64": "0.25.0", + "@esbuild/darwin-x64": "0.25.0", + "@esbuild/freebsd-arm64": "0.25.0", + "@esbuild/freebsd-x64": "0.25.0", + "@esbuild/linux-arm": "0.25.0", + "@esbuild/linux-arm64": "0.25.0", + "@esbuild/linux-ia32": "0.25.0", + "@esbuild/linux-loong64": "0.25.0", + "@esbuild/linux-mips64el": "0.25.0", + "@esbuild/linux-ppc64": "0.25.0", + "@esbuild/linux-riscv64": "0.25.0", + "@esbuild/linux-s390x": "0.25.0", + "@esbuild/linux-x64": "0.25.0", + "@esbuild/netbsd-arm64": "0.25.0", + "@esbuild/netbsd-x64": "0.25.0", + "@esbuild/openbsd-arm64": "0.25.0", + "@esbuild/openbsd-x64": "0.25.0", + "@esbuild/sunos-x64": "0.25.0", + "@esbuild/win32-arm64": "0.25.0", + "@esbuild/win32-ia32": "0.25.0", + "@esbuild/win32-x64": "0.25.0" } }, "node_modules/escalade": { @@ -4677,9 +4670,9 @@ } }, "node_modules/eslint-config-prettier": { - "version": "10.0.1", - "resolved": "https://registry.npmmirror.com/eslint-config-prettier/-/eslint-config-prettier-10.0.1.tgz", - "integrity": "sha512-lZBts941cyJyeaooiKxAtzoPHTN+GbQTJFAIdQbRhA4/8whaAraEh47Whw/ZFfrjNSnlAxqfm9i0XVAEkULjCw==", + "version": "10.0.2", + "resolved": "https://registry.npmmirror.com/eslint-config-prettier/-/eslint-config-prettier-10.0.2.tgz", + "integrity": "sha512-1105/17ZIMjmCOJOPNfVdbXafLCLj3hPmkmB7dLgt7XsQ/zkxSuDerE/xgO3RxoHysR1N1whmquY0lSn2O0VLg==", "dev": true, "bin": { "eslint-config-prettier": "build/bin/cli.js" @@ -4709,19 +4702,18 @@ } }, "node_modules/eslint-import-resolver-typescript": { - "version": "3.7.0", - "resolved": "https://registry.npmmirror.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.7.0.tgz", - "integrity": "sha512-Vrwyi8HHxY97K5ebydMtffsWAn1SCR9eol49eCd5fJS4O1WV7PaAjbcjmbfJJSMz/t4Mal212Uz/fQZrOB8mow==", + "version": "3.8.3", + "resolved": "https://registry.npmmirror.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.8.3.tgz", + "integrity": "sha512-A0bu4Ks2QqDWNpeEgTQMPTngaMhuDu4yv6xpftBMAf+1ziXnpx+eSR1WRfoPTe2BAiAjHFZ7kSNx1fvr5g5pmQ==", "dev": true, "dependencies": { "@nolyfill/is-core-module": "1.0.39", "debug": "^4.3.7", "enhanced-resolve": "^5.15.0", - "fast-glob": "^3.3.2", - "get-tsconfig": "^4.7.5", + "get-tsconfig": "^4.10.0", "is-bun-module": "^1.0.2", - "is-glob": "^4.0.3", - "stable-hash": "^0.0.4" + "stable-hash": "^0.0.4", + "tinyglobby": "^0.2.12" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -4885,9 +4877,9 @@ } }, "node_modules/eslint-plugin-react-hooks": { - "version": "5.1.0", - "resolved": "https://registry.npmmirror.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.1.0.tgz", - "integrity": "sha512-mpJRtPgHN2tNAvZ35AMfqeB3Xqeo273QxrHJsbBEPWODRM4r0yB6jfoROqKEYrOn27UtRPpcpHc2UqyBSuUNTw==", + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", "dev": true, "engines": { "node": ">=10" @@ -5414,9 +5406,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.8.1", - "resolved": "https://registry.npmmirror.com/get-tsconfig/-/get-tsconfig-4.8.1.tgz", - "integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==", + "version": "4.10.0", + "resolved": "https://registry.npmmirror.com/get-tsconfig/-/get-tsconfig-4.10.0.tgz", + "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", "dev": true, "dependencies": { "resolve-pkg-maps": "^1.0.0" @@ -5646,9 +5638,9 @@ } }, "node_modules/i18next-browser-languagedetector": { - "version": "8.0.2", - "resolved": "https://registry.npmmirror.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.2.tgz", - "integrity": "sha512-shBvPmnIyZeD2VU5jVGIOWP7u9qNG3Lj7mpaiPFpbJ3LVfHZJvVzKR4v1Cb91wAOFpNw442N+LGPzHOHsten2g==", + "version": "8.0.4", + "resolved": "https://registry.npmmirror.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.4.tgz", + "integrity": "sha512-f3frU3pIxD50/Tz20zx9TD9HobKYg47fmAETb117GKGPrhwcSSPJDoCposXlVycVebQ9GQohC3Efbpq7/nnJ5w==", "dependencies": { "@babel/runtime": "^7.23.2" } @@ -6332,9 +6324,9 @@ } }, "node_modules/lucide-react": { - "version": "0.475.0", - "resolved": "https://registry.npmmirror.com/lucide-react/-/lucide-react-0.475.0.tgz", - "integrity": "sha512-NJzvVu1HwFVeZ+Gwq2q00KygM1aBhy/ZrhY9FsAgJtpB+E4R7uxRk9M2iKvHa6/vNxZydIB59htha4c2vvwvVg==", + "version": "0.477.0", + "resolved": "https://registry.npmmirror.com/lucide-react/-/lucide-react-0.477.0.tgz", + "integrity": "sha512-yCf7aYxerFZAbd8jHJxjwe1j7jEMPptjnaOqdYeirFnEy85cNR3/L+o0I875CYFYya+eEVzZSbNuRk8BZPDpVw==", "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } @@ -6450,9 +6442,9 @@ } }, "node_modules/nanoid": { - "version": "5.0.9", - "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-5.0.9.tgz", - "integrity": "sha512-Aooyr6MXU6HpvvWXKoVoXwKMs/KyVakWwg7xQfv5/S/RIgJMy0Ifa45H9qqYy7pTCszrHzP21Uk4PZq2HpEM8Q==", + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-5.1.2.tgz", + "integrity": "sha512-b+CiXQCNMUGe0Ri64S9SXFcP9hogjAJ2Rd6GdVxhPLRm7mhGaM7VgOvCAJ1ZshfHbqVDI3uqTI5C8/GaKuLI7g==", "funding": [ { "type": "github", @@ -6795,9 +6787,9 @@ } }, "node_modules/pocketbase": { - "version": "0.25.1", - "resolved": "https://registry.npmmirror.com/pocketbase/-/pocketbase-0.25.1.tgz", - "integrity": "sha512-2IH0KLI/qMNR/E17C7BGWX2FxW7Tead+igLHOWZ45P56v/NyVT18Jnmddeft+3qWWGL1Hog2F8bc4orWV/+Fcg==" + "version": "0.25.2", + "resolved": "https://registry.npmmirror.com/pocketbase/-/pocketbase-0.25.2.tgz", + "integrity": "sha512-ONZl1+qHJMnhR2uacBlBJ90lm7njtL/zy0606+1ROfK9hSL4LRBRc8r89rMcNRzPzRqCNyoFTh2Qg/lYXdEC1w==" }, "node_modules/possible-typed-array-names": { "version": "1.0.0", @@ -6809,9 +6801,9 @@ } }, "node_modules/postcss": { - "version": "8.5.2", - "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.2.tgz", - "integrity": "sha512-MjOadfU3Ys9KYoX0AdkBlFEF1Vx37uCCeN4ZHnmwm9FfpbsGWMZeBLMmmpY+6Ocqod7mkdZ0DT31OlbsFrLlkA==", + "version": "8.5.3", + "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", "dev": true, "funding": [ { @@ -6979,9 +6971,9 @@ } }, "node_modules/prettier": { - "version": "3.5.0", - "resolved": "https://registry.npmmirror.com/prettier/-/prettier-3.5.0.tgz", - "integrity": "sha512-quyMrVt6svPS7CjQ9gKb3GLEX/rl3BCL2oa/QkNcXv4YNVBC9olt3s+H7ukto06q7B1Qz46PbrKLO34PR6vXcA==", + "version": "3.5.3", + "resolved": "https://registry.npmmirror.com/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -7058,9 +7050,9 @@ } }, "node_modules/rc-cascader": { - "version": "3.33.0", - "resolved": "https://registry.npmmirror.com/rc-cascader/-/rc-cascader-3.33.0.tgz", - "integrity": "sha512-JvZrMbKBXIbEDmpIORxqvedY/bck6hGbs3hxdWT8eS9wSQ1P7//lGxbyKjOSyQiVBbgzNWriSe6HoMcZO/+0rQ==", + "version": "3.33.1", + "resolved": "https://registry.npmmirror.com/rc-cascader/-/rc-cascader-3.33.1.tgz", + "integrity": "sha512-Kyl4EJ7ZfCBuidmZVieegcbFw0RcU5bHHSbtEdmuLYd0fYHCAiYKZ6zon7fWAVyC6rWWOOib0XKdTSf7ElC9rg==", "dependencies": { "@babel/runtime": "^7.25.7", "classnames": "^2.3.1", @@ -7184,9 +7176,9 @@ } }, "node_modules/rc-input": { - "version": "1.7.2", - "resolved": "https://registry.npmmirror.com/rc-input/-/rc-input-1.7.2.tgz", - "integrity": "sha512-g3nYONnl4edWj2FfVoxsU3Ec4XTE+Hb39Kfh2MFxMZjp/0gGyPUgy/v7ZhS27ZxUFNkuIDYXm9PJsLyJbtg86A==", + "version": "1.7.3", + "resolved": "https://registry.npmmirror.com/rc-input/-/rc-input-1.7.3.tgz", + "integrity": "sha512-A5w4egJq8+4JzlQ55FfQjDnPvOaAbzwC3VLOAdOytyek3TboSOP9qxN+Gifup+shVXfvecBLBbWBpWxmk02SWQ==", "dependencies": { "@babel/runtime": "^7.11.1", "classnames": "^2.2.1", @@ -7232,9 +7224,9 @@ } }, "node_modules/rc-menu": { - "version": "9.16.0", - "resolved": "https://registry.npmmirror.com/rc-menu/-/rc-menu-9.16.0.tgz", - "integrity": "sha512-vAL0yqPkmXWk3+YKRkmIR8TYj3RVdEt3ptG2jCJXWNAvQbT0VJJdRyHZ7kG/l1JsZlB+VJq/VcYOo69VR4oD+w==", + "version": "9.16.1", + "resolved": "https://registry.npmmirror.com/rc-menu/-/rc-menu-9.16.1.tgz", + "integrity": "sha512-ghHx6/6Dvp+fw8CJhDUHFHDJ84hJE3BXNCzSgLdmNiFErWSOaZNsihDAsKq9ByTALo/xkNIwtDFGIl6r+RPXBg==", "dependencies": { "@babel/runtime": "^7.10.1", "@rc-component/trigger": "^2.0.0", @@ -7310,9 +7302,9 @@ } }, "node_modules/rc-picker": { - "version": "4.11.1", - "resolved": "https://registry.npmmirror.com/rc-picker/-/rc-picker-4.11.1.tgz", - "integrity": "sha512-qHaZrHrYjAVwMcKqMXJz9xHifQgQpKSav0E1ejOe3SFTHZggPlmKzLnA5i//Y4DEumR4HZEsePSOdOlmX1JvAw==", + "version": "4.11.3", + "resolved": "https://registry.npmmirror.com/rc-picker/-/rc-picker-4.11.3.tgz", + "integrity": "sha512-MJ5teb7FlNE0NFHTncxXQ62Y5lytq6sh5nUw0iH8OkHL/TjARSEvSHpr940pWgjGANpjCwyMdvsEV55l5tYNSg==", "dependencies": { "@babel/runtime": "^7.24.7", "@rc-component/trigger": "^2.0.0", @@ -7478,9 +7470,9 @@ } }, "node_modules/rc-table": { - "version": "7.50.2", - "resolved": "https://registry.npmmirror.com/rc-table/-/rc-table-7.50.2.tgz", - "integrity": "sha512-+nJbzxzstBriLb5sr9U7Vjs7+4dO8cWlouQbMwBVYghk2vr508bBdkHJeP/z9HVjAIKmAgMQKxmtbgDd3gc5wA==", + "version": "7.50.3", + "resolved": "https://registry.npmmirror.com/rc-table/-/rc-table-7.50.3.tgz", + "integrity": "sha512-Z4/zNCzjv7f/XzPRecb+vJU0DJKdsYt4YRkDzNl4G05m7JmxrKGYC2KqN1Ew6jw2zJq7cxVv3z39qyZOHMuf7A==", "dependencies": { "@babel/runtime": "^7.10.1", "@rc-component/context": "^1.4.0", @@ -7550,9 +7542,9 @@ } }, "node_modules/rc-tree": { - "version": "5.13.0", - "resolved": "https://registry.npmmirror.com/rc-tree/-/rc-tree-5.13.0.tgz", - "integrity": "sha512-2+lFvoVRnvHQ1trlpXMOWtF8BUgF+3TiipG72uOfhpL5CUdXCk931kvDdUkTL/IZVtNEDQKwEEmJbAYJSA5NnA==", + "version": "5.13.1", + "resolved": "https://registry.npmmirror.com/rc-tree/-/rc-tree-5.13.1.tgz", + "integrity": "sha512-FNhIefhftobCdUJshO7M8uZTA9F4OPGVXqGfZkkD/5soDeOhwO06T/aKTrg0WD8gRg/pyfq+ql3aMymLHCTC4A==", "dependencies": { "@babel/runtime": "^7.10.1", "classnames": "2.x", @@ -7670,9 +7662,9 @@ "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" }, "node_modules/react-i18next": { - "version": "15.4.0", - "resolved": "https://registry.npmmirror.com/react-i18next/-/react-i18next-15.4.0.tgz", - "integrity": "sha512-Py6UkX3zV08RTvL6ZANRoBh9sL/ne6rQq79XlkHEdd82cZr2H9usbWpUNVadJntIZP2pu3M2rL1CN+5rQYfYFw==", + "version": "15.4.1", + "resolved": "https://registry.npmmirror.com/react-i18next/-/react-i18next-15.4.1.tgz", + "integrity": "sha512-ahGab+IaSgZmNPYXdV1n+OYky95TGpFwnKRflX/16dY04DsYYKHtVLjeny7sBSCREEcoMbAgSkFiGLF5g5Oofw==", "dependencies": { "@babel/runtime": "^7.25.0", "html-parse-stringify": "^3.0.1" @@ -7710,9 +7702,9 @@ } }, "node_modules/react-router": { - "version": "7.1.5", - "resolved": "https://registry.npmmirror.com/react-router/-/react-router-7.1.5.tgz", - "integrity": "sha512-8BUF+hZEU4/z/JD201yK6S+UYhsf58bzYIDq2NS1iGpwxSXDu7F+DeGSkIXMFBuHZB21FSiCzEcUb18cQNdRkA==", + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/react-router/-/react-router-7.2.0.tgz", + "integrity": "sha512-fXyqzPgCPZbqhrk7k3hPcCpYIlQ2ugIXDboHUzhJISFVy2DEPsmHgN588MyGmkIOv3jDgNfUE3kJi83L28s/LQ==", "dependencies": { "@types/cookie": "^0.6.0", "cookie": "^1.0.1", @@ -7733,11 +7725,11 @@ } }, "node_modules/react-router-dom": { - "version": "7.1.5", - "resolved": "https://registry.npmmirror.com/react-router-dom/-/react-router-dom-7.1.5.tgz", - "integrity": "sha512-/4f9+up0Qv92D3bB8iN5P1s3oHAepSGa9h5k6tpTFlixTTskJZwKGhJ6vRJ277tLD1zuaZTt95hyGWV1Z37csQ==", + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/react-router-dom/-/react-router-dom-7.2.0.tgz", + "integrity": "sha512-cU7lTxETGtQRQbafJubvZKHEn5izNABxZhBY0Jlzdv0gqQhCPQt2J8aN5ZPjS6mQOXn5NnirWNh+FpE8TTYN0Q==", "dependencies": { - "react-router": "7.1.5" + "react-router": "7.2.0" }, "engines": { "node": ">=20.0.0" @@ -8711,6 +8703,48 @@ "resolved": "https://registry.npmmirror.com/tinycolor2/-/tinycolor2-1.6.0.tgz", "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==" }, + "node_modules/tinyglobby": { + "version": "0.2.12", + "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.12.tgz", + "integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==", + "dev": true, + "dependencies": { + "fdir": "^6.4.3", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.3", + "resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.4.3.tgz", + "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", + "dev": true, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -8879,9 +8913,9 @@ } }, "node_modules/typescript": { - "version": "5.7.3", - "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.7.3.tgz", - "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "version": "5.8.2", + "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.8.2.tgz", + "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", "devOptional": true, "bin": { "tsc": "bin/tsc", @@ -9018,13 +9052,13 @@ "dev": true }, "node_modules/vite": { - "version": "6.1.0", - "resolved": "https://registry.npmmirror.com/vite/-/vite-6.1.0.tgz", - "integrity": "sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ==", + "version": "6.2.0", + "resolved": "https://registry.npmmirror.com/vite/-/vite-6.2.0.tgz", + "integrity": "sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ==", "dev": true, "dependencies": { - "esbuild": "^0.24.2", - "postcss": "^8.5.1", + "esbuild": "^0.25.0", + "postcss": "^8.5.3", "rollup": "^4.30.1" }, "bin": { diff --git a/ui/package.json b/ui/package.json index b3a9c756..d72a318a 100644 --- a/ui/package.json +++ b/ui/package.json @@ -11,25 +11,25 @@ }, "dependencies": { "@ant-design/icons": "^5.6.1", - "@ant-design/pro-components": "^2.8.5", + "@ant-design/pro-components": "^2.8.6", "ahooks": "^3.8.4", - "antd": "^5.24.0", + "antd": "^5.24.3", "antd-zod": "^6.0.1", "clsx": "^2.1.1", - "cron-parser": "^4.9.0", + "cron-parser": "^5.0.4", "file-saver": "^2.0.5", "i18next": "^24.2.2", - "i18next-browser-languagedetector": "^8.0.2", + "i18next-browser-languagedetector": "^8.0.4", "immer": "^10.1.1", - "lucide-react": "^0.475.0", - "nanoid": "^5.0.9", - "pocketbase": "^0.25.1", + "lucide-react": "^0.477.0", + "nanoid": "^5.1.2", + "pocketbase": "^0.25.2", "radash": "^12.1.0", "react": "^18.3.1", "react-copy-to-clipboard": "^5.1.0", "react-dom": "^18.3.1", - "react-i18next": "^15.4.0", - "react-router-dom": "^7.1.5", + "react-i18next": "^15.4.1", + "react-router-dom": "^7.2.0", "tailwind-merge": "^2.6.0", "zod": "^3.24.2", "zustand": "^5.0.3" @@ -37,29 +37,29 @@ "devDependencies": { "@types/file-saver": "^2.0.7", "@types/fs-extra": "^11.0.4", - "@types/node": "^22.10.7", + "@types/node": "^22.13.9", "@types/react": "^18.3.12", "@types/react-copy-to-clipboard": "^5.0.7", "@types/react-dom": "^18.3.1", - "@typescript-eslint/eslint-plugin": "^8.24.0", - "@typescript-eslint/parser": "^8.24.0", - "@vitejs/plugin-legacy": "^6.0.1", + "@typescript-eslint/eslint-plugin": "^8.26.0", + "@typescript-eslint/parser": "^8.26.0", + "@vitejs/plugin-legacy": "^6.0.2", "@vitejs/plugin-react": "^4.3.4", "autoprefixer": "^10.4.20", "eslint": "^8.57.0", - "eslint-config-prettier": "^10.0.1", - "eslint-import-resolver-typescript": "^3.7.0", + "eslint-config-prettier": "^10.0.2", + "eslint-import-resolver-typescript": "^3.8.3", "eslint-plugin-import": "^2.31.0", "eslint-plugin-prettier": "^5.2.3", - "eslint-plugin-react-hooks": "^5.1.0", + "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.19", "eslint-plugin-tailwindcss": "^3.18.0", "fs-extra": "^11.3.0", - "postcss": "^8.5.2", - "prettier": "^3.5.0", + "postcss": "^8.5.3", + "prettier": "^3.5.3", "tailwindcss": "^3.4.17", "tailwindcss-animate": "^1.0.7", - "typescript": "^5.7.3", - "vite": "^6.1.0" + "typescript": "^5.8.2", + "vite": "^6.2.0" } } diff --git a/ui/public/imgs/providers/1panel.svg b/ui/public/imgs/providers/1panel.svg new file mode 100644 index 00000000..561199ce --- /dev/null +++ b/ui/public/imgs/providers/1panel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ui/src/components/access/AccessForm.tsx b/ui/src/components/access/AccessForm.tsx index 47c6d8c6..7f2143ac 100644 --- a/ui/src/components/access/AccessForm.tsx +++ b/ui/src/components/access/AccessForm.tsx @@ -9,6 +9,7 @@ import { type AccessModel } from "@/domain/access"; import { ACCESS_PROVIDERS } from "@/domain/provider"; import { useAntdForm, useAntdFormName } from "@/hooks"; +import AccessForm1PanelConfig from "./AccessForm1PanelConfig"; import AccessFormACMEHttpReqConfig from "./AccessFormACMEHttpReqConfig"; import AccessFormAliyunConfig from "./AccessFormAliyunConfig"; import AccessFormAWSConfig from "./AccessFormAWSConfig"; @@ -99,6 +100,8 @@ const AccessForm = forwardRef(({ className, NOTICE: If you add new child component, please keep ASCII order. */ switch (fieldProvider) { + case ACCESS_PROVIDERS["1PANEL"]: + return ; case ACCESS_PROVIDERS.ACMEHTTPREQ: return ; case ACCESS_PROVIDERS.ALIYUN: diff --git a/ui/src/components/access/AccessForm1PanelConfig.tsx b/ui/src/components/access/AccessForm1PanelConfig.tsx new file mode 100644 index 00000000..1dde96b5 --- /dev/null +++ b/ui/src/components/access/AccessForm1PanelConfig.tsx @@ -0,0 +1,85 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input, Switch } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import { type AccessConfigFor1Panel } from "@/domain/access"; + +type AccessForm1PanelConfigFieldValues = Nullish; + +export type AccessForm1PanelConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: AccessForm1PanelConfigFieldValues; + onValuesChange?: (values: AccessForm1PanelConfigFieldValues) => void; +}; + +const initFormModel = (): AccessForm1PanelConfigFieldValues => { + return { + apiUrl: "http://:20410/", + apiKey: "", + }; +}; + +const AccessForm1PanelConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessForm1PanelConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + apiUrl: z.string().url(t("common.errmsg.url_invalid")), + apiKey: z + .string() + .min(1, t("access.form.1panel_api_key.placeholder")) + .max(64, t("common.errmsg.string_max", { max: 64 })) + .trim(), + allowInsecureConnections: z.boolean().nullish(), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ } + > + + + + } + > + + + + } + > + + +
+ ); +}; + +export default AccessForm1PanelConfig; diff --git a/ui/src/components/access/AccessFormBaotaPanelConfig.tsx b/ui/src/components/access/AccessFormBaotaPanelConfig.tsx index accd80d0..fa9c4723 100644 --- a/ui/src/components/access/AccessFormBaotaPanelConfig.tsx +++ b/ui/src/components/access/AccessFormBaotaPanelConfig.tsx @@ -1,5 +1,5 @@ import { useTranslation } from "react-i18next"; -import { Form, type FormInstance, Input } from "antd"; +import { Form, type FormInstance, Input, Switch } from "antd"; import { createSchemaFieldRule } from "antd-zod"; import { z } from "zod"; @@ -17,7 +17,7 @@ export type AccessFormBaotaPanelConfigProps = { const initFormModel = (): AccessFormBaotaPanelConfigFieldValues => { return { - apiUrl: "http://:8888/", + apiUrl: "http://:8888/", apiKey: "", }; }; @@ -32,6 +32,7 @@ const AccessFormBaotaPanelConfig = ({ form: formInst, formName, disabled, initia .min(1, t("access.form.baotapanel_api_key.placeholder")) .max(64, t("common.errmsg.string_max", { max: 64 })) .trim(), + allowInsecureConnections: z.boolean().nullish(), }); const formRule = createSchemaFieldRule(formSchema); @@ -65,6 +66,18 @@ const AccessFormBaotaPanelConfig = ({ form: formInst, formName, disabled, initia > + + } + > + + ); }; diff --git a/ui/src/components/access/AccessFormCdnflyConfig.tsx b/ui/src/components/access/AccessFormCdnflyConfig.tsx index a9dd1139..ec0afaa2 100644 --- a/ui/src/components/access/AccessFormCdnflyConfig.tsx +++ b/ui/src/components/access/AccessFormCdnflyConfig.tsx @@ -17,7 +17,7 @@ export type AccessFormCdnflyConfigProps = { const initFormModel = (): AccessFormCdnflyConfigFieldValues => { return { - apiUrl: "http://:88/", + apiUrl: "http://:88/", apiKey: "", apiSecret: "", }; diff --git a/ui/src/components/access/AccessFormPowerDNSConfig.tsx b/ui/src/components/access/AccessFormPowerDNSConfig.tsx index e93980c7..cada5b61 100644 --- a/ui/src/components/access/AccessFormPowerDNSConfig.tsx +++ b/ui/src/components/access/AccessFormPowerDNSConfig.tsx @@ -17,7 +17,7 @@ export type AccessFormPowerDNSConfigProps = { const initFormModel = (): AccessFormPowerDNSConfigFieldValues => { return { - apiUrl: "http://:8082/", + apiUrl: "http://:8082/", apiKey: "", }; }; diff --git a/ui/src/components/access/AccessFormSafeLineConfig.tsx b/ui/src/components/access/AccessFormSafeLineConfig.tsx index b9de115c..5b16c508 100644 --- a/ui/src/components/access/AccessFormSafeLineConfig.tsx +++ b/ui/src/components/access/AccessFormSafeLineConfig.tsx @@ -1,5 +1,5 @@ import { useTranslation } from "react-i18next"; -import { Form, type FormInstance, Input } from "antd"; +import { Form, type FormInstance, Input, Switch } from "antd"; import { createSchemaFieldRule } from "antd-zod"; import { z } from "zod"; @@ -17,7 +17,7 @@ export type AccessFormSafeLineConfigProps = { const initFormModel = (): AccessFormSafeLineConfigFieldValues => { return { - apiUrl: "http://:9443/", + apiUrl: "http://:9443/", apiToken: "", }; }; @@ -32,6 +32,7 @@ const AccessFormSafeLineConfig = ({ form: formInst, formName, disabled, initialV .min(1, t("access.form.safeline_api_token.placeholder")) .max(64, t("common.errmsg.string_max", { max: 64 })) .trim(), + allowInsecureConnections: z.boolean().nullish(), }); const formRule = createSchemaFieldRule(formSchema); @@ -65,6 +66,18 @@ const AccessFormSafeLineConfig = ({ form: formInst, formName, disabled, initialV > + + } + > + + ); }; diff --git a/ui/src/components/access/AccessFormWebhookConfig.tsx b/ui/src/components/access/AccessFormWebhookConfig.tsx index 60f55fe6..89280d79 100644 --- a/ui/src/components/access/AccessFormWebhookConfig.tsx +++ b/ui/src/components/access/AccessFormWebhookConfig.tsx @@ -1,5 +1,5 @@ import { useTranslation } from "react-i18next"; -import { Form, type FormInstance, Input } from "antd"; +import { Form, type FormInstance, Input, Switch } from "antd"; import { createSchemaFieldRule } from "antd-zod"; import { z } from "zod"; @@ -26,6 +26,7 @@ const AccessFormWebhookConfig = ({ form: formInst, formName, disabled, initialVa const formSchema = z.object({ url: z.string({ message: t("access.form.webhook_url.placeholder") }).url(t("common.errmsg.url_invalid")), + allowInsecureConnections: z.boolean().nullish(), }); const formRule = createSchemaFieldRule(formSchema); @@ -45,6 +46,18 @@ const AccessFormWebhookConfig = ({ form: formInst, formName, disabled, initialVa + + } + > + + ); }; diff --git a/ui/src/components/notification/NotifyChannelEditFormBarkFields.tsx b/ui/src/components/notification/NotifyChannelEditFormBarkFields.tsx index f5e4944d..154b870a 100644 --- a/ui/src/components/notification/NotifyChannelEditFormBarkFields.tsx +++ b/ui/src/components/notification/NotifyChannelEditFormBarkFields.tsx @@ -13,8 +13,7 @@ const NotifyChannelEditFormBarkFields = () => { .nullish(), deviceKey: z .string({ message: t("settings.notification.channel.form.bark_device_key.placeholder") }) - .min(1, t("settings.notification.channel.form.bark_device_key.placeholder")) - .max(256, t("common.errmsg.string_max", { max: 256 })), + .nonempty(t("settings.notification.channel.form.bark_device_key.placeholder")), }); const formRule = createSchemaFieldRule(formSchema); diff --git a/ui/src/components/notification/NotifyChannelEditFormDingTalkFields.tsx b/ui/src/components/notification/NotifyChannelEditFormDingTalkFields.tsx index 9543f142..f7daa4bf 100644 --- a/ui/src/components/notification/NotifyChannelEditFormDingTalkFields.tsx +++ b/ui/src/components/notification/NotifyChannelEditFormDingTalkFields.tsx @@ -9,12 +9,10 @@ const NotifyChannelEditFormDingTalkFields = () => { const formSchema = z.object({ accessToken: z .string({ message: t("settings.notification.channel.form.dingtalk_access_token.placeholder") }) - .min(1, t("settings.notification.channel.form.dingtalk_access_token.placeholder")) - .max(256, t("common.errmsg.string_max", { max: 256 })), + .nonempty(t("settings.notification.channel.form.dingtalk_access_token.placeholder")), secret: z .string({ message: t("settings.notification.channel.form.dingtalk_secret.placeholder") }) - .min(1, t("settings.notification.channel.form.dingtalk_secret.placeholder")) - .max(64, t("common.errmsg.string_max", { max: 64 })), + .nonempty(t("settings.notification.channel.form.dingtalk_secret.placeholder")), }); const formRule = createSchemaFieldRule(formSchema); diff --git a/ui/src/components/notification/NotifyChannelEditFormWeComFields.tsx b/ui/src/components/notification/NotifyChannelEditFormWeComFields.tsx index 1dddbbc4..645653a4 100644 --- a/ui/src/components/notification/NotifyChannelEditFormWeComFields.tsx +++ b/ui/src/components/notification/NotifyChannelEditFormWeComFields.tsx @@ -7,10 +7,7 @@ const NotifyChannelEditFormWeComFields = () => { const { t } = useTranslation(); const formSchema = z.object({ - webhookUrl: z - .string({ message: t("settings.notification.channel.form.wecom_webhook_url.placeholder") }) - .min(1, t("settings.notification.channel.form.wecom_webhook_url.placeholder")) - .url({ message: t("common.errmsg.url_invalid") }), + webhookUrl: z.string({ message: t("settings.notification.channel.form.wecom_webhook_url.placeholder") }).url({ message: t("common.errmsg.url_invalid") }), }); const formRule = createSchemaFieldRule(formSchema); diff --git a/ui/src/components/notification/NotifyChannels.tsx b/ui/src/components/notification/NotifyChannels.tsx index 8dacecb9..50bc881d 100644 --- a/ui/src/components/notification/NotifyChannels.tsx +++ b/ui/src/components/notification/NotifyChannels.tsx @@ -98,8 +98,8 @@ const NotifyChannels = ({ className, classNames, style, styles }: NotifyChannels handleSwitchChange(channel.type, checked)} /> diff --git a/ui/src/components/provider/DeployProviderPicker.tsx b/ui/src/components/provider/DeployProviderPicker.tsx index 57ba39a6..cc34ef16 100644 --- a/ui/src/components/provider/DeployProviderPicker.tsx +++ b/ui/src/components/provider/DeployProviderPicker.tsx @@ -64,6 +64,7 @@ const DeployProviderPicker = ({ className, style, autoFocus, placeholder, onSele DEPLOY_CATEGORIES.LOADBALANCE, DEPLOY_CATEGORIES.FIREWALL, DEPLOY_CATEGORIES.AV, + DEPLOY_CATEGORIES.SERVERLESS, DEPLOY_CATEGORIES.WEBSITE, DEPLOY_CATEGORIES.OTHER, ].map((key) => ({ diff --git a/ui/src/components/workflow/WorkflowElementsContainer.tsx b/ui/src/components/workflow/WorkflowElementsContainer.tsx index 2329eeac..3dc2bd6d 100644 --- a/ui/src/components/workflow/WorkflowElementsContainer.tsx +++ b/ui/src/components/workflow/WorkflowElementsContainer.tsx @@ -14,6 +14,10 @@ export type WorkflowElementsProps = { const WorkflowElementsContainer = ({ className, style, disabled }: WorkflowElementsProps) => { const [scale, setScale] = useState(1); + const MIN_SCALE = 0.2; + const MAX_SCALE = 2; + const STEP_SCALE = 0.05; + return (
@@ -28,9 +32,9 @@ const WorkflowElementsContainer = ({ className, style, disabled }: WorkflowEleme
-
diff --git a/ui/src/components/workflow/node/DeployNodeConfigForm.tsx b/ui/src/components/workflow/node/DeployNodeConfigForm.tsx index b9f65b08..4f05c1c8 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigForm.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigForm.tsx @@ -15,12 +15,15 @@ import { type WorkflowNode, type WorkflowNodeConfigForDeploy } from "@/domain/wo import { useAntdForm, useAntdFormName, useZustandShallowSelector } from "@/hooks"; import { useWorkflowStore } from "@/stores/workflow"; +import DeployNodeConfigForm1PanelConsoleConfig from "./DeployNodeConfigForm1PanelConsoleConfig"; +import DeployNodeConfigForm1PanelSiteConfig from "./DeployNodeConfigForm1PanelSiteConfig"; import DeployNodeConfigFormAliyunALBConfig from "./DeployNodeConfigFormAliyunALBConfig"; import DeployNodeConfigFormAliyunCASDeployConfig from "./DeployNodeConfigFormAliyunCASDeployConfig"; import DeployNodeConfigFormAliyunCDNConfig from "./DeployNodeConfigFormAliyunCDNConfig"; import DeployNodeConfigFormAliyunCLBConfig from "./DeployNodeConfigFormAliyunCLBConfig"; import DeployNodeConfigFormAliyunDCDNConfig from "./DeployNodeConfigFormAliyunDCDNConfig"; import DeployNodeConfigFormAliyunESAConfig from "./DeployNodeConfigFormAliyunESAConfig"; +import DeployNodeConfigFormAliyunFCConfig from "./DeployNodeConfigFormAliyunFCConfig"; import DeployNodeConfigFormAliyunLiveConfig from "./DeployNodeConfigFormAliyunLiveConfig"; import DeployNodeConfigFormAliyunNLBConfig from "./DeployNodeConfigFormAliyunNLBConfig"; import DeployNodeConfigFormAliyunOSSConfig from "./DeployNodeConfigFormAliyunOSSConfig"; @@ -55,6 +58,7 @@ import DeployNodeConfigFormTencentCloudCOSConfig from "./DeployNodeConfigFormTen import DeployNodeConfigFormTencentCloudCSSConfig from "./DeployNodeConfigFormTencentCloudCSSConfig.tsx"; import DeployNodeConfigFormTencentCloudECDNConfig from "./DeployNodeConfigFormTencentCloudECDNConfig.tsx"; import DeployNodeConfigFormTencentCloudEOConfig from "./DeployNodeConfigFormTencentCloudEOConfig.tsx"; +import DeployNodeConfigFormTencentCloudSCFConfig from "./DeployNodeConfigFormTencentCloudSCFConfig"; import DeployNodeConfigFormTencentCloudSSLDeployConfig from "./DeployNodeConfigFormTencentCloudSSLDeployConfig"; import DeployNodeConfigFormTencentCloudVODConfig from "./DeployNodeConfigFormTencentCloudVODConfig"; import DeployNodeConfigFormTencentCloudWAFConfig from "./DeployNodeConfigFormTencentCloudWAFConfig"; @@ -138,6 +142,10 @@ const DeployNodeConfigForm = forwardRef; + case DEPLOY_PROVIDERS["1PANEL_SITE"]: + return ; case DEPLOY_PROVIDERS.ALIYUN_ALB: return ; case DEPLOY_PROVIDERS.ALIYUN_CAS_DEPLOY: @@ -150,6 +158,8 @@ const DeployNodeConfigForm = forwardRef; case DEPLOY_PROVIDERS.ALIYUN_ESA: return ; + case DEPLOY_PROVIDERS.ALIYUN_FC: + return ; case DEPLOY_PROVIDERS.ALIYUN_LIVE: return ; case DEPLOY_PROVIDERS.ALIYUN_NLB: @@ -218,6 +228,8 @@ const DeployNodeConfigForm = forwardRef; case DEPLOY_PROVIDERS.TENCENTCLOUD_EO: return ; + case DEPLOY_PROVIDERS.TENCENTCLOUD_SCF: + return ; case DEPLOY_PROVIDERS.TENCENTCLOUD_SSL_DEPLOY: return ; case DEPLOY_PROVIDERS.TENCENTCLOUD_VOD: @@ -427,8 +439,8 @@ const DeployNodeConfigForm = forwardRef{t("workflow_node.deploy.form.skip_on_last_succeeded.prefix")}
{t("workflow_node.deploy.form.skip_on_last_succeeded.suffix")}
diff --git a/ui/src/components/workflow/node/DeployNodeConfigForm1PanelConsoleConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigForm1PanelConsoleConfig.tsx new file mode 100644 index 00000000..349b516e --- /dev/null +++ b/ui/src/components/workflow/node/DeployNodeConfigForm1PanelConsoleConfig.tsx @@ -0,0 +1,56 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Switch } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +type DeployNodeConfigForm1PanelConsoleConfigFieldValues = Nullish<{ + autoRestart?: boolean; +}>; + +export type DeployNodeConfigForm1PanelConsoleConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: DeployNodeConfigForm1PanelConsoleConfigFieldValues; + onValuesChange?: (values: DeployNodeConfigForm1PanelConsoleConfigFieldValues) => void; +}; + +const initFormModel = (): DeployNodeConfigForm1PanelConsoleConfigFieldValues => { + return {}; +}; + +const DeployNodeConfigForm1PanelConsoleConfig = ({ + form: formInst, + formName, + disabled, + initialValues, + onValuesChange, +}: DeployNodeConfigForm1PanelConsoleConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + autoRestart: z.boolean().nullish(), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ + + +
+ ); +}; + +export default DeployNodeConfigForm1PanelConsoleConfig; diff --git a/ui/src/components/workflow/node/DeployNodeConfigForm1PanelSiteConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigForm1PanelSiteConfig.tsx new file mode 100644 index 00000000..f5a26450 --- /dev/null +++ b/ui/src/components/workflow/node/DeployNodeConfigForm1PanelSiteConfig.tsx @@ -0,0 +1,63 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +type DeployNodeConfigForm1PanelSiteConfigFieldValues = Nullish<{ + websiteId: string | number; +}>; + +export type DeployNodeConfigForm1PanelSiteConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: DeployNodeConfigForm1PanelSiteConfigFieldValues; + onValuesChange?: (values: DeployNodeConfigForm1PanelSiteConfigFieldValues) => void; +}; + +const initFormModel = (): DeployNodeConfigForm1PanelSiteConfigFieldValues => { + return {}; +}; + +const DeployNodeConfigForm1PanelSiteConfig = ({ + form: formInst, + formName, + disabled, + initialValues, + onValuesChange, +}: DeployNodeConfigForm1PanelSiteConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + websiteId: z.union([z.string(), z.number()]).refine((v) => { + return /^\d+$/.test(v + "") && +v > 0; + }, t("workflow_node.deploy.form.1panel_site_website_id.placeholder")), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ } + > + + +
+ ); +}; + +export default DeployNodeConfigForm1PanelSiteConfig; diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormAliyunFCConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunFCConfig.tsx new file mode 100644 index 00000000..87212953 --- /dev/null +++ b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunFCConfig.tsx @@ -0,0 +1,90 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input, Select } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import { validDomainName } from "@/utils/validators"; + +type DeployNodeConfigFormAliyunFCConfigFieldValues = Nullish<{ + region: string; + serviceVersion: string; + domain: string; +}>; + +export type DeployNodeConfigFormAliyunFCConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: DeployNodeConfigFormAliyunFCConfigFieldValues; + onValuesChange?: (values: DeployNodeConfigFormAliyunFCConfigFieldValues) => void; +}; + +const initFormModel = (): DeployNodeConfigFormAliyunFCConfigFieldValues => { + return { + serviceVersion: "3.0", + }; +}; + +const DeployNodeConfigFormAliyunFCConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: DeployNodeConfigFormAliyunFCConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + serviceVersion: z.union([z.literal("2.0"), z.literal("3.0")], { + message: t("workflow_node.deploy.form.aliyun_fc_service_version.placeholder"), + }), + region: z + .string({ message: t("workflow_node.deploy.form.aliyun_fc_region.placeholder") }) + .nonempty(t("workflow_node.deploy.form.aliyun_fc_region.placeholder")) + .trim(), + domain: z + .string({ message: t("workflow_node.deploy.form.aliyun_fc_domain.placeholder") }) + .refine((v) => validDomainName(v), t("common.errmsg.domain_invalid")), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ + + + + } + > + + + + } + > + + +
+ ); +}; + +export default DeployNodeConfigFormAliyunFCConfig; diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudSCFConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudSCFConfig.tsx new file mode 100644 index 00000000..6758ddbd --- /dev/null +++ b/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudSCFConfig.tsx @@ -0,0 +1,79 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import { validDomainName } from "@/utils/validators"; + +type DeployNodeConfigFormTencentCloudSCFConfigFieldValues = Nullish<{ + region: string; + domain: string; +}>; + +export type DeployNodeConfigFormTencentCloudSCFConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: DeployNodeConfigFormTencentCloudSCFConfigFieldValues; + onValuesChange?: (values: DeployNodeConfigFormTencentCloudSCFConfigFieldValues) => void; +}; + +const initFormModel = (): DeployNodeConfigFormTencentCloudSCFConfigFieldValues => { + return {}; +}; + +const DeployNodeConfigFormTencentCloudSCFConfig = ({ + form: formInst, + formName, + disabled, + initialValues, + onValuesChange, +}: DeployNodeConfigFormTencentCloudSCFConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + region: z + .string({ message: t("workflow_node.deploy.form.tencentcloud_scf_region.placeholder") }) + .nonempty(t("workflow_node.deploy.form.tencentcloud_scf_region.placeholder")) + .trim(), + domain: z + .string({ message: t("workflow_node.deploy.form.tencentcloud_scf_domain.placeholder") }) + .refine((v) => validDomainName(v), t("common.errmsg.domain_invalid")), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ } + > + + + + } + > + + +
+ ); +}; + +export default DeployNodeConfigFormTencentCloudSCFConfig; diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudSSLDeployConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudSSLDeployConfig.tsx index 67cdbf11..0f52609f 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudSSLDeployConfig.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudSSLDeployConfig.tsx @@ -80,6 +80,15 @@ const DeployNodeConfigFormTencentCloudSSLDeployConfig = ({ + } + > + + + } diff --git a/ui/src/components/workflow/node/_SharedNode.tsx b/ui/src/components/workflow/node/_SharedNode.tsx index fec24a6a..ae981451 100644 --- a/ui/src/components/workflow/node/_SharedNode.tsx +++ b/ui/src/components/workflow/node/_SharedNode.tsx @@ -258,12 +258,13 @@ const SharedNodeConfigDrawer = ({ const handleClose = () => { if (pending) return; - const oldValues = Object.fromEntries(Object.entries(node.config ?? {}).filter(([_, value]) => value !== null && value !== undefined)); - const newValues = Object.fromEntries(Object.entries(getFormValues()).filter(([_, value]) => value !== null && value !== undefined)); + const oldValues = JSON.parse(JSON.stringify(node.config ?? {})); + const newValues = JSON.parse(JSON.stringify(getFormValues())); const changed = !isEqual(oldValues, {}) && !isEqual(oldValues, newValues); const { promise, resolve, reject } = Promise.withResolvers(); if (changed) { + console.log(oldValues, newValues); modalApi.confirm({ title: t("common.text.operation_confirm"), content: t("workflow_node.unsaved_changes.confirm"), diff --git a/ui/src/domain/access.ts b/ui/src/domain/access.ts index d32960ca..1b5adf45 100644 --- a/ui/src/domain/access.ts +++ b/ui/src/domain/access.ts @@ -6,6 +6,7 @@ export interface AccessModel extends BaseModel { NOTICE: If you add new type, please keep ASCII order. */ Record & ( + | AccessConfigFor1Panel | AccessConfigForACMEHttpReq | AccessConfigForAliyun | AccessConfigForAWS @@ -46,6 +47,12 @@ export interface AccessModel extends BaseModel { } // #region AccessConfig +export type AccessConfigFor1Panel = { + apiUrl: string; + apiKey: string; + allowInsecureConnections?: boolean; +}; + export type AccessConfigForACMEHttpReq = { endpoint: string; mode?: string; @@ -82,6 +89,7 @@ export type AccessConfigForBaishan = { export type AccessConfigForBaotaPanel = { apiUrl: string; apiKey: string; + allowInsecureConnections?: boolean; }; export type AccessConfigForBytePlus = { @@ -193,6 +201,7 @@ export type AccessConfigForRainYun = { export type AccessConfigForSafeLine = { apiUrl: string; apiToken: string; + allowInsecureConnections?: boolean; }; export type AccessConfigForSSH = { @@ -222,6 +231,7 @@ export type AccessConfigForVolcEngine = { export type AccessConfigForWebhook = { url: string; + allowInsecureConnections?: boolean; }; export type AccessConfigForWestcn = { diff --git a/ui/src/domain/provider.ts b/ui/src/domain/provider.ts index 0841f39d..f3d6deb3 100644 --- a/ui/src/domain/provider.ts +++ b/ui/src/domain/provider.ts @@ -4,6 +4,7 @@ NOTICE: If you add new constant, please keep ASCII order. */ export const ACCESS_PROVIDERS = Object.freeze({ + ["1PANEL"]: "1panel", ACMEHTTPREQ: "acmehttpreq", ALIYUN: "aliyun", AWS: "aws", @@ -84,6 +85,7 @@ export const accessProvidersMap: Map { + return node.type === WorkflowNodeType.Branch || node.type === WorkflowNodeType.ExecuteResultBranch; +}; + type InitWorkflowOptions = { template?: "standard"; }; @@ -191,6 +196,9 @@ export const initWorkflow = (options: InitWorkflowOptions = {}): WorkflowModel = current.next = newNode(WorkflowNodeType.Deploy, {}); current = current.next; + current.next = newNode(WorkflowNodeType.ExecuteResultBranch, {}); + + current = current.next!.branches![1]; current.next = newNode(WorkflowNodeType.Notify, {}); } @@ -265,14 +273,27 @@ export const updateNode = (node: WorkflowNode, targetNode: WorkflowNode) => { let current = draft; while (current) { if (current.id === targetNode.id) { - Object.assign(current, targetNode); + // Object.assign(current, targetNode); + // TODO: 暂时这么处理,避免 #485 #489,后续再优化 + current.type = targetNode.type; + current.name = targetNode.name; + current.config = targetNode.config; + current.inputs = targetNode.inputs; + current.outputs = targetNode.outputs; + current.next = targetNode.next; + current.branches = targetNode.branches; + current.validated = targetNode.validated; break; } - if (current.type === WorkflowNodeType.Branch || current.type === WorkflowNodeType.ExecuteResultBranch) { - current.branches = current.branches!.map((branch) => updateNode(branch, targetNode)); + + if (isBranchLike(current)) { + current.branches ??= []; + current.branches = current.branches.map((branch) => updateNode(branch, targetNode)); } + current = current.next as WorkflowNode; } + return draft; }); }; @@ -281,20 +302,24 @@ export const addNode = (node: WorkflowNode, previousNodeId: string, targetNode: return produce(node, (draft) => { let current = draft; while (current) { - if (current.id === previousNodeId && targetNode.type !== WorkflowNodeType.Branch && targetNode.type !== WorkflowNodeType.ExecuteResultBranch) { + if (current.id === previousNodeId && !isBranchLike(targetNode)) { targetNode.next = current.next; current.next = targetNode; break; - } else if (current.id === previousNodeId && (targetNode.type === WorkflowNodeType.Branch || targetNode.type === WorkflowNodeType.ExecuteResultBranch)) { + } else if (current.id === previousNodeId && isBranchLike(targetNode)) { targetNode.branches![0].next = current.next; current.next = targetNode; break; } - if (current.type === WorkflowNodeType.Branch || current.type === WorkflowNodeType.ExecuteResultBranch) { - current.branches = current.branches!.map((branch) => addNode(branch, previousNodeId, targetNode)); + + if (isBranchLike(current)) { + current.branches ??= []; + current.branches = current.branches.map((branch) => addNode(branch, previousNodeId, targetNode)); } + current = current.next as WorkflowNode; } + return draft; }); }; @@ -307,18 +332,24 @@ export const addBranch = (node: WorkflowNode, branchNodeId: string) => { if (current.type !== WorkflowNodeType.Branch) { return draft; } - current.branches!.push( + + current.branches ??= []; + current.branches.push( newNode(WorkflowNodeType.Condition, { - branchIndex: current.branches!.length, + branchIndex: current.branches.length, }) ); break; } - if (current.type === WorkflowNodeType.Branch || current.type === WorkflowNodeType.ExecuteResultBranch) { - current.branches = current.branches!.map((branch) => addBranch(branch, branchNodeId)); + + if (isBranchLike(current)) { + current.branches ??= []; + current.branches = current.branches.map((branch) => addBranch(branch, branchNodeId)); } + current = current.next as WorkflowNode; } + return draft; }); }; @@ -331,11 +362,15 @@ export const removeNode = (node: WorkflowNode, targetNodeId: string) => { current.next = current.next.next; break; } - if (current.type === WorkflowNodeType.Branch || current.type === WorkflowNodeType.ExecuteResultBranch) { - current.branches = current.branches!.map((branch) => removeNode(branch, targetNodeId)); + + if (isBranchLike(current)) { + current.branches ??= []; + current.branches = current.branches.map((branch) => removeNode(branch, targetNodeId)); } + current = current.next as WorkflowNode; } + return draft; }); }; @@ -351,14 +386,16 @@ export const removeBranch = (node: WorkflowNode, branchNodeId: string, branchInd }; while (current && last) { if (current.id === branchNodeId) { - if (current.type !== WorkflowNodeType.Branch && current.type !== WorkflowNodeType.ExecuteResultBranch) { + if (!isBranchLike(current)) { return draft; } - current.branches!.splice(branchIndex, 1); + + current.branches ??= []; + current.branches.splice(branchIndex, 1); // 如果仅剩一个分支,删除分支节点,将分支节点的下一个节点挂载到当前节点 - if (current.branches!.length === 1) { - const branch = current.branches![0]; + if (current.branches.length === 1) { + const branch = current.branches[0]; if (branch.next) { last.next = branch.next; let lastNode: WorkflowNode | undefined = branch.next; @@ -373,19 +410,23 @@ export const removeBranch = (node: WorkflowNode, branchNodeId: string, branchInd break; } - if (current.type === WorkflowNodeType.Branch || current.type === WorkflowNodeType.ExecuteResultBranch) { - current.branches = current.branches!.map((branch) => removeBranch(branch, branchNodeId, branchIndex)); + + if (isBranchLike(current)) { + current.branches ??= []; + current.branches = current.branches.map((branch) => removeBranch(branch, branchNodeId, branchIndex)); } + current = current.next as WorkflowNode; last = last.next; } + return draft; }); }; -export const getWorkflowOutputBeforeId = (root: WorkflowNode, nodeId: string, type: string): WorkflowNode[] => { - // 1 个分支的节点,不应该能获取到相邻分支上节点的输出 - const output: WorkflowNode[] = []; +export const getOutputBeforeNodeId = (root: WorkflowNode, nodeId: string, type: string): WorkflowNode[] => { + // 某个分支的节点,不应该能获取到相邻分支上节点的输出 + const outputs: WorkflowNode[] = []; const traverse = (current: WorkflowNode, output: WorkflowNode[]) => { if (!current) { @@ -395,7 +436,7 @@ export const getWorkflowOutputBeforeId = (root: WorkflowNode, nodeId: string, ty return true; } - // 如果当前节点是execute_failure,清除execute_result_branch节点前一个节点的输出 + // 如果当前节点是 ExecuteFailure,清除 ExecuteResultBranch 节点前一个节点的输出 if (current.type === WorkflowNodeType.ExecuteFailure) { output.splice(output.length - 1); } @@ -407,7 +448,7 @@ export const getWorkflowOutputBeforeId = (root: WorkflowNode, nodeId: string, ty }); } - if (current.type === WorkflowNodeType.Branch || current.type === WorkflowNodeType.ExecuteResultBranch) { + if (isBranchLike(current)) { const currentLength = output.length; for (const branch of current.branches!) { if (traverse(branch, output)) { @@ -423,14 +464,14 @@ export const getWorkflowOutputBeforeId = (root: WorkflowNode, nodeId: string, ty return traverse(current.next as WorkflowNode, output); }; - traverse(root, output); - return output; + traverse(root, outputs); + return outputs; }; export const isAllNodesValidated = (node: WorkflowNode): boolean => { let current = node as typeof node | undefined; while (current) { - if (current.type === WorkflowNodeType.Branch || current.type === WorkflowNodeType.ExecuteResultBranch) { + if (isBranchLike(current)) { for (const branch of current.branches!) { if (!isAllNodesValidated(branch)) { return false; diff --git a/ui/src/i18n/locales/en/nls.access.json b/ui/src/i18n/locales/en/nls.access.json index ff6115a9..b3884dd4 100644 --- a/ui/src/i18n/locales/en/nls.access.json +++ b/ui/src/i18n/locales/en/nls.access.json @@ -23,6 +23,16 @@ "access.form.provider.label": "Provider", "access.form.provider.placeholder": "Please select a provider", "access.form.provider.tooltip": "DNS provider: The provider that hosts your domain names and manages your DNS records.
Host provider: The provider that hosts your servers or cloud services for deploying certificates.

Cannot be edited after saving.", + "access.form.1panel_api_url.label": "1Panel URL", + "access.form.1panel_api_url.placeholder": "Please enter 1Panel URL", + "access.form.1panel_api_url.tooltip": "For more information, see https://docs.1panel.pro/dev_manual/api_manual/", + "access.form.1panel_api_key.label": "1Panel API key", + "access.form.1panel_api_key.placeholder": "Please enter 1Panel API key", + "access.form.1panel_api_key.tooltip": "For more information, see https://docs.1panel.pro/dev_manual/api_manual/", + "access.form.1panel_allow_insecure_conns.label": "Insecure SSL/TLS connections", + "access.form.1panel_allow_insecure_conns.tooltip": "Allowing insecure connections may lead to data leak or tampering. Use this option only when under trusted networks.", + "access.form.1panel_allow_insecure_conns.switch.on": "Allow", + "access.form.1panel_allow_insecure_conns.switch.off": "Disallow", "access.form.acmehttpreq_endpoint.label": "Endpoint", "access.form.acmehttpreq_endpoint.placeholder": "Please enter endpoint", "access.form.acmehttpreq_endpoint.tooltip": "For more information, see https://go-acme.github.io/lego/dns/httpreq/", @@ -73,6 +83,10 @@ "access.form.baotapanel_api_key.label": "aaPanel API key", "access.form.baotapanel_api_key.placeholder": "Please enter aaPanel API key", "access.form.baotapanel_api_key.tooltip": "For more information, see https://www.bt.cn/bbs/thread-20376-1-1.html", + "access.form.baotapanel_allow_insecure_conns.label": "Insecure SSL/TLS connections", + "access.form.baotapanel_allow_insecure_conns.tooltip": "Allowing insecure connections may lead to data leak or tampering. Use this option only when under trusted networks.", + "access.form.baotapanel_allow_insecure_conns.switch.on": "Allow", + "access.form.baotapanel_allow_insecure_conns.switch.off": "Disallow", "access.form.byteplus_access_key.label": "BytePlus AccessKey", "access.form.byteplus_access_key.placeholder": "Please enter BytePlus AccessKey", "access.form.byteplus_access_key.tooltip": "For more information, see https://docs.byteplus.com/en/docs/byteplus-platform/docs-managing-keys", @@ -194,6 +208,10 @@ "access.form.safeline_api_token.label": "SafeLine API token", "access.form.safeline_api_token.placeholder": "Please enter SafeLine API token", "access.form.safeline_api_token.tooltip": "For more information, see https://docs.waf.chaitin.com/en/reference/articles/openapi", + "access.form.safeline_allow_insecure_conns.label": "Insecure SSL/TLS connections", + "access.form.safeline_allow_insecure_conns.tooltip": "Allowing insecure connections may lead to data leak or tampering. Use this option only when under trusted networks.", + "access.form.safeline_allow_insecure_conns.switch.on": "Allow", + "access.form.safeline_allow_insecure_conns.switch.off": "Disallow", "access.form.ssh_host.label": "Server host", "access.form.ssh_host.placeholder": "Please enter server host", "access.form.ssh_port.label": "Server port", @@ -233,6 +251,10 @@ "access.form.volcengine_secret_access_key.tooltip": "For more information, see https://www.volcengine.com/docs/6291/216571", "access.form.webhook_url.label": "Webhook URL", "access.form.webhook_url.placeholder": "Please enter Webhook URL", + "access.form.webhook_allow_insecure_conns.label": "Insecure SSL/TLS connections", + "access.form.webhook_allow_insecure_conns.tooltip": "Allowing insecure connections may lead to data leak or tampering. Use this option only when under trusted networks.", + "access.form.webhook_allow_insecure_conns.switch.on": "Allow", + "access.form.webhook_allow_insecure_conns.switch.off": "Disallow", "access.form.westcn_username.label": "West.cn username", "access.form.westcn_username.placeholder": "Please enter West.cn username", "access.form.westcn_username.tooltip": "For more information, see https://www.west.cn/CustomerCenter/doc/apiv2.html", diff --git a/ui/src/i18n/locales/en/nls.provider.json b/ui/src/i18n/locales/en/nls.provider.json index 9ce0bc5c..4c6091e1 100644 --- a/ui/src/i18n/locales/en/nls.provider.json +++ b/ui/src/i18n/locales/en/nls.provider.json @@ -1,5 +1,7 @@ { "provider.1panel": "1Panel", + "provider.1panel.console": "1Panel - Console", + "provider.1panel.site": "1Panel - Website", "provider.acmehttpreq": "Http Request (ACME Proxy)", "provider.aliyun": "Alibaba Cloud", "provider.aliyun.alb": "Alibaba Cloud - ALB (Application Load Balancer)", @@ -9,6 +11,7 @@ "provider.aliyun.dcdn": "Alibaba Cloud - DCDN (Dynamic Route for Content Delivery Network)", "provider.aliyun.dns": "Alibaba Cloud - DNS (Domain Name Service)", "provider.aliyun.esa": "Alibaba Cloud - ESA (Edge Security Acceleration)", + "provider.aliyun.fc": "Alibaba Cloud - FC (Function Compute)", "provider.aliyun.live": "Alibaba Cloud - ApsaraVideo Live", "provider.aliyun.nlb": "Alibaba Cloud - NLB (Network Load Balancer)", "provider.aliyun.oss": "Alibaba Cloud - OSS (Object Storage Service)", @@ -28,7 +31,7 @@ "provider.baishan.cdn": "Baishan - CDN (Content Delivery Network)", "provider.baotapanel": "aaPanel (aka BaoTaPanel)", "provider.baotapanel.console": "aaPanel (aka BaoTaPanel) - Console", - "provider.baotapanel.site": "aaPanel (aka BaoTaPanel) - Site", + "provider.baotapanel.site": "aaPanel (aka BaoTaPanel) - Website", "provider.byteplus": "BytePlus", "provider.byteplus.cdn": "BytePlus - CDN (Content Delivery Network)", "provider.cachefly": "CacheFly", @@ -83,6 +86,7 @@ "provider.tencentcloud.dns": "Tencent Cloud - DNS (Domain Name Service)", "provider.tencentcloud.ecdn": "Tencent Cloud - ECDN (Enterprise Content Delivery Network)", "provider.tencentcloud.eo": "Tencent Cloud - EdgeOne", + "provider.tencentcloud.scf": "Tencent Cloud - SCF (Serverless Cloud Function)", "provider.tencentcloud.ssl_deploy": "Tencent Cloud - via SSL Certificate Service Deployment Job", "provider.tencentcloud.vod": "Tencent Cloud - VOD (Video on Demand)", "provider.tencentcloud.waf": "Tencent Cloud - WAF (Web Application Firewall)", @@ -106,6 +110,7 @@ "provider.category.loadbalance": "Loadbalance", "provider.category.firewall": "Firewall", "provider.category.av": "Audio/Video", + "provider.category.serverless": "Serverless", "provider.category.website": "Website", "provider.category.other": "Other" } diff --git a/ui/src/i18n/locales/en/nls.settings.json b/ui/src/i18n/locales/en/nls.settings.json index 0bb6ba40..f4b3c85f 100644 --- a/ui/src/i18n/locales/en/nls.settings.json +++ b/ui/src/i18n/locales/en/nls.settings.json @@ -16,7 +16,7 @@ "settings.password.form.password.errmsg.not_matched": "Passwords do not match", "settings.notification.tab": "Notification", - "settings.notification.template.card.title": "Template", + "settings.notification.template.card.title": "Certificate expiration notification template", "settings.notification.template.form.subject.label": "Subject", "settings.notification.template.form.subject.placeholder": "Please enter notification subject", "settings.notification.template.form.subject.extra": "Supported variables (${COUNT}: number of expiring soon)", @@ -24,8 +24,8 @@ "settings.notification.template.form.message.placeholder": "Please enter notification message", "settings.notification.template.form.message.extra": "Supported variables (${COUNT}: number of expiring soon. ${DOMAINS}: Domain list)", "settings.notification.channels.card.title": "Channels", - "settings.notification.channel.enabled.on": "On", - "settings.notification.channel.enabled.off": "Off", + "settings.notification.channel.switch.on": "On", + "settings.notification.channel.switch.off": "Off", "settings.notification.push_test.button": "Send test notification", "settings.notification.push_test.pushed": "Sent", "settings.notification.channel.form.bark_server_url.label": "Server URL", @@ -44,7 +44,7 @@ "settings.notification.channel.form.email_smtp_host.placeholder": "Please enter SMTP host", "settings.notification.channel.form.email_smtp_port.label": "SMTP port", "settings.notification.channel.form.email_smtp_port.placeholder": "Please enter SMTP port", - "settings.notification.channel.form.email_smtp_tls.label": "Use TLS/SSL", + "settings.notification.channel.form.email_smtp_tls.label": "Use SSL/TLS", "settings.notification.channel.form.email_username.label": "Username", "settings.notification.channel.form.email_username.placeholder": "please enter username", "settings.notification.channel.form.email_password.label": "Password", diff --git a/ui/src/i18n/locales/en/nls.workflow.nodes.json b/ui/src/i18n/locales/en/nls.workflow.nodes.json index 16f698fa..4035755c 100644 --- a/ui/src/i18n/locales/en/nls.workflow.nodes.json +++ b/ui/src/i18n/locales/en/nls.workflow.nodes.json @@ -20,7 +20,7 @@ "workflow_node.start.form.trigger_cron.errmsg.invalid": "Please enter a valid cron expression", "workflow_node.start.form.trigger_cron.tooltip": "Exactly 5 space separated segments. Time zone is based on the server.", "workflow_node.start.form.trigger_cron.extra": "Expected execution time for the last 5 times:", - "workflow_node.start.form.trigger_cron.guide": "Tips: If you have multiple workflows, it is recommended to set them to run at multiple times of the day instead of always running at specific times.

Reference links:
1. Let’s Encrypt rate limits
2. Why should my Let’s Encrypt (ACME) client run at a random time?", + "workflow_node.start.form.trigger_cron.guide": "Tips: If you have multiple workflows, it is recommended to set them to run at multiple times of the day instead of always running at specific times. Don't always set it to midnight every day to avoid spikes in traffic.

Reference links:
1. Let’s Encrypt rate limits
2. Why should my Let’s Encrypt (ACME) client run at a random time?", "workflow_node.apply.label": "Application", "workflow_node.apply.form.domains.label": "Domains", @@ -90,6 +90,10 @@ "workflow_node.deploy.form.certificate.placeholder": "Please select certificate", "workflow_node.deploy.form.certificate.tooltip": "The certificate to be deployed comes from the previous application stage node.", "workflow_node.deploy.form.params_config.label": "Parameter settings", + "workflow_node.deploy.form.1panel_console_auto_restart.label": "Auto restart after deployment", + "workflow_node.deploy.form.1panel_site_website_id.label": "1Panel website ID", + "workflow_node.deploy.form.1panel_site_website_id.placeholder": "Please enter 1Panel website ID", + "workflow_node.deploy.form.1panel_site_website_id.tooltip": "You can find it on 1Panel WebUI.", "workflow_node.deploy.form.aliyun_alb_resource_type.label": "Resource type", "workflow_node.deploy.form.aliyun_alb_resource_type.placeholder": "Please select resource type", "workflow_node.deploy.form.aliyun_alb_resource_type.option.loadbalancer.label": "ALB load balancer", @@ -150,6 +154,14 @@ "workflow_node.deploy.form.aliyun_esa_site_id.label": "Alibaba Cloud ESA site ID", "workflow_node.deploy.form.aliyun_esa_site_id.placeholder": "Please enter Alibaba Cloud ESA site ID", "workflow_node.deploy.form.aliyun_esa_site_id.tooltip": "For more information, see https://esa.console.aliyun.com/siteManage/list", + "workflow_node.deploy.form.aliyun_fc_region.label": "Alibaba Cloud FC region", + "workflow_node.deploy.form.aliyun_fc_region.placeholder": "Please enter Alibaba Cloud FC region (e.g. cn-hangzhou)", + "workflow_node.deploy.form.aliyun_fc_region.tooltip": "For more information, see https://www.alibabacloud.com/help/en/functioncompute/fc-3-0/product-overview/supported-regions", + "workflow_node.deploy.form.aliyun_fc_service_version.label": "Alibaba Cloud FC version", + "workflow_node.deploy.form.aliyun_fc_service_version.placeholder": "Please select Alibaba Cloud FC version", + "workflow_node.deploy.form.aliyun_fc_domain.label": "Alibaba Cloud FC domain", + "workflow_node.deploy.form.aliyun_fc_domain.placeholder": "Please enter Alibaba Cloud FC domain name", + "workflow_node.deploy.form.aliyun_fc_domain.tooltip": "For more information, see https://fcnext.console.aliyun.com", "workflow_node.deploy.form.aliyun_live_region.label": "Alibaba Cloud Live region", "workflow_node.deploy.form.aliyun_live_region.placeholder": "Please enter Alibaba Cloud Live region (e.g. cn-hangzhou)", "workflow_node.deploy.form.aliyun_live_region.tooltip": "For more information, see https://www.alibabacloud.com/help/en/live/product-overview/supported-regions", @@ -341,9 +353,9 @@ "workflow_node.deploy.form.local_shell_env.option.sh.label": "POSIX Bash (on Linux / macOS)", "workflow_node.deploy.form.local_shell_env.option.cmd.label": "CMD (on Windows)", "workflow_node.deploy.form.local_shell_env.option.powershell.label": "PowerShell (on Windows)", - "workflow_node.deploy.form.local_pre_command.label": "Pre-command", + "workflow_node.deploy.form.local_pre_command.label": "Pre-command (Optional)", "workflow_node.deploy.form.local_pre_command.placeholder": "Please enter command to be executed before saving files", - "workflow_node.deploy.form.local_post_command.label": "Post-command", + "workflow_node.deploy.form.local_post_command.label": "Post-command (Optional)", "workflow_node.deploy.form.local_post_command.placeholder": "Please enter command to be executed after saving files", "workflow_node.deploy.form.local_preset_scripts.button": "Use preset scripts", "workflow_node.deploy.form.local_preset_scripts.option.reload_nginx.label": "POSIX Bash - Reload nginx", @@ -388,9 +400,9 @@ "workflow_node.deploy.form.ssh_jks_storepass.tooltip": "For more information, see https://docs.oracle.com/cd/E19509-01/820-3503/ggfen/index.html", "workflow_node.deploy.form.ssh_shell_env.label": "Shell", "workflow_node.deploy.form.ssh_shell_env.value": "POSIX Bash (on Linux / macOS)", - "workflow_node.deploy.form.ssh_pre_command.label": "Pre-command", + "workflow_node.deploy.form.ssh_pre_command.label": "Pre-command (Optional)", "workflow_node.deploy.form.ssh_pre_command.placeholder": "Please enter command to be executed before uploading files", - "workflow_node.deploy.form.ssh_post_command.label": "Post-command", + "workflow_node.deploy.form.ssh_post_command.label": "Post-command (Optional)", "workflow_node.deploy.form.ssh_post_command.placeholder": "Please enter command to be executed after uploading files", "workflow_node.deploy.form.ssh_preset_scripts.button": "Use preset scripts", "workflow_node.deploy.form.ssh_preset_scripts.option.reload_nginx.label": "POSIX Bash - Reload nginx", @@ -441,10 +453,19 @@ "workflow_node.deploy.form.tencentcloud_eo_domain.label": "Tencent Cloud EdgeOne domain", "workflow_node.deploy.form.tencentcloud_eo_domain.placeholder": "Please enter Tencent Cloud EdgeOne domain name", "workflow_node.deploy.form.tencentcloud_eo_domain.tooltip": "For more information, see https://console.tencentcloud.com/edgeone", + "workflow_node.deploy.form.tencentcloud_scf_region.label": "Tencent Cloud SCF region", + "workflow_node.deploy.form.tencentcloud_scf_region.placeholder": "Please enter Tencent Cloud SCF region (e.g. ap-guangzhou)", + "workflow_node.deploy.form.tencentcloud_scf_region.tooltip": "For more information, see https://www.tencentcloud.com/document/product/583/17299", + "workflow_node.deploy.form.tencentcloud_scf_domain.label": "Tencent Cloud SCF domain", + "workflow_node.deploy.form.tencentcloud_scf_domain.placeholder": "Please enter Tencent Cloud SCF domain name", + "workflow_node.deploy.form.tencentcloud_scf_domain.tooltip": "For more information, see https://console.tencentcloud.com/scf", "workflow_node.deploy.form.tencentcloud_ssl_deploy.guide": "TIPS: You need to go to the Tencent Cloud console to check the actual deployment results by yourself, because Tencent Cloud deployment tasks are running asynchronously.", "workflow_node.deploy.form.tencentcloud_ssl_deploy_region.label": "Tencent Cloud service region", "workflow_node.deploy.form.tencentcloud_ssl_deploy_region.placeholder": "Please enter Tencent Cloud service region (e.g. ap-guangzhou)", "workflow_node.deploy.form.tencentcloud_ssl_deploy_region.tooltip": "For more information, see https://www.tencentcloud.com/document/product/1007/36573", + "workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_type.label": "Tencent Cloud resource type", + "workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_type.placeholder": "Please enter Tencent Cloud resource type", + "workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_type.tooltip": "For more information, see https://cloud.tencent.com.cn/document/product/400/91667", "workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_ids.label": "Tencent Cloud resource IDs", "workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_ids.placeholder": "Please enter Tencent Cloud resource IDs (separated by semicolons)", "workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_ids.errmsg.invalid": "Please enter a valid Tencent Cloud resource ID", @@ -526,8 +547,8 @@ "workflow_node.deploy.form.skip_on_last_succeeded.label": "Repeated deployment", "workflow_node.deploy.form.skip_on_last_succeeded.prefix": "If the last deployment was successful, ", "workflow_node.deploy.form.skip_on_last_succeeded.suffix": " to re-deploy.", - "workflow_node.deploy.form.skip_on_last_succeeded.enabled.on": "skip", - "workflow_node.deploy.form.skip_on_last_succeeded.enabled.off": "not skip", + "workflow_node.deploy.form.skip_on_last_succeeded.switch.on": "skip", + "workflow_node.deploy.form.skip_on_last_succeeded.switch.off": "not skip", "workflow_node.notify.label": "Notification", "workflow_node.notify.form.subject.label": "Subject", diff --git a/ui/src/i18n/locales/zh/nls.access.json b/ui/src/i18n/locales/zh/nls.access.json index 64b034d5..d72cd259 100644 --- a/ui/src/i18n/locales/zh/nls.access.json +++ b/ui/src/i18n/locales/zh/nls.access.json @@ -23,6 +23,16 @@ "access.form.provider.label": "提供商", "access.form.provider.placeholder": "请选择提供商", "access.form.provider.tooltip": "提供商分为两种类型:
【DNS 提供商】你的 DNS 托管方,通常等同于域名注册商,用于在申请证书时管理您的域名解析记录。
【主机提供商】你的服务器或云服务的托管方,用于部署签发的证书。

该字段保存后不可修改。", + "access.form.1panel_api_url.label": "1Panel URL", + "access.form.1panel_api_url.placeholder": "请输入 1Panel URL", + "access.form.1panel_api_url.tooltip": "这是什么?请参阅 https://1panel.cn/docs/dev_manual/api_manual/", + "access.form.1panel_api_key.label": "1Panel 接口密钥", + "access.form.1panel_api_key.placeholder": "请输入 1Panel 接口密钥", + "access.form.1panel_api_key.tooltip": "这是什么?请参阅 https://1panel.cn/docs/dev_manual/api_manual/", + "access.form.1panel_allow_insecure_conns.label": "忽略 SSL/TLS 证书错误", + "access.form.1panel_allow_insecure_conns.tooltip": "忽略 SSL/TLS 证书错误可能导致数据泄露或被篡改。建议仅在可信网络下启用。", + "access.form.1panel_allow_insecure_conns.switch.on": "允许", + "access.form.1panel_allow_insecure_conns.switch.off": "不允许", "access.form.acmehttpreq_endpoint.label": "服务端点", "access.form.acmehttpreq_endpoint.placeholder": "请输入服务端点", "access.form.acmehttpreq_endpoint.tooltip": "这是什么?请参阅 https://go-acme.github.io/lego/dns/httpreq/", @@ -73,6 +83,10 @@ "access.form.baotapanel_api_key.label": "宝塔面板接口密钥", "access.form.baotapanel_api_key.placeholder": "请输入宝塔面板接口密钥", "access.form.baotapanel_api_key.tooltip": "这是什么?请参阅 https://www.bt.cn/bbs/thread-113890-1-1.html", + "access.form.baotapanel_allow_insecure_conns.label": "忽略 SSL/TLS 证书错误", + "access.form.baotapanel_allow_insecure_conns.tooltip": "忽略 SSL/TLS 证书错误可能导致数据泄露或被篡改。建议仅在可信网络下启用。", + "access.form.baotapanel_allow_insecure_conns.switch.on": "允许", + "access.form.baotapanel_allow_insecure_conns.switch.off": "不允许", "access.form.byteplus_access_key.label": "BytePlus AccessKey", "access.form.byteplus_access_key.placeholder": "请输入 BytePlus AccessKey", "access.form.byteplus_access_key.tooltip": "这是什么?请参阅 https://docs.byteplus.com/zh-CN/docs/byteplus-platform/docs-managing-keys", @@ -194,6 +208,10 @@ "access.form.safeline_api_token.label": "雷池 API Token", "access.form.safeline_api_token.placeholder": "请输入雷池 API Token", "access.form.safeline_api_token.tooltip": "这是什么?请参阅 https://docs.waf-ce.chaitin.cn/zh/更多技术文档/OPENAPI", + "access.form.safeline_allow_insecure_conns.label": "忽略 SSL/TLS 证书错误", + "access.form.safeline_allow_insecure_conns.tooltip": "忽略 SSL/TLS 证书错误可能导致数据泄露或被篡改。建议仅在可信网络下启用。", + "access.form.safeline_allow_insecure_conns.switch.on": "允许", + "access.form.safeline_allow_insecure_conns.switch.off": "不允许", "access.form.ssh_host.label": "服务器地址", "access.form.ssh_host.placeholder": "请输入服务器地址", "access.form.ssh_port.label": "服务器端口", @@ -233,6 +251,10 @@ "access.form.volcengine_secret_access_key.tooltip": "这是什么?请参阅 https://www.volcengine.com/docs/6291/216571", "access.form.webhook_url.label": "Webhook 回调地址", "access.form.webhook_url.placeholder": "请输入 Webhook 回调地址", + "access.form.webhook_allow_insecure_conns.label": "忽略 SSL/TLS 证书错误", + "access.form.webhook_allow_insecure_conns.tooltip": "忽略 SSL/TLS 证书错误可能导致数据泄露或被篡改。建议仅在可信网络下启用。", + "access.form.webhook_allow_insecure_conns.switch.on": "允许", + "access.form.webhook_allow_insecure_conns.switch.off": "不允许", "access.form.westcn_username.label": "西部数码用户名", "access.form.westcn_username.placeholder": "请输入西部数码用户名", "access.form.westcn_username.tooltip": "这是什么?请参阅 https://www.west.cn/CustomerCenter/doc/apiv2.html", diff --git a/ui/src/i18n/locales/zh/nls.provider.json b/ui/src/i18n/locales/zh/nls.provider.json index f8d36830..e8580e41 100644 --- a/ui/src/i18n/locales/zh/nls.provider.json +++ b/ui/src/i18n/locales/zh/nls.provider.json @@ -1,5 +1,7 @@ { "provider.1panel": "1Panel", + "provider.1panel.console": "1Panel - 面板", + "provider.1panel.site": "1Panel - 网站", "provider.acmehttpreq": "Http Request (ACME Proxy)", "provider.aliyun": "阿里云", "provider.aliyun.alb": "阿里云 - 应用型负载均衡 ALB", @@ -8,6 +10,7 @@ "provider.aliyun.clb": "阿里云 - 传统型负载均衡 CLB", "provider.aliyun.dcdn": "阿里云 - 全站加速 DCDN", "provider.aliyun.esa": "阿里云 - 边缘安全加速 ESA", + "provider.aliyun.fc": "阿里云 - 函数计算 FC", "provider.aliyun.dns": "阿里云 - 云解析 DNS", "provider.aliyun.live": "阿里云 - 视频直播 Live", "provider.aliyun.nlb": "阿里云 - 网络型负载均衡 NLB", @@ -83,6 +86,7 @@ "provider.tencentcloud.dns": "腾讯云 - 云解析 DNS", "provider.tencentcloud.ecdn": "腾讯云 - 全站加速网络 ECDN", "provider.tencentcloud.eo": "腾讯云 - 边缘安全加速平台 EdgeOne", + "provider.tencentcloud.scf": "腾讯云 - 云函数 SCF", "provider.tencentcloud.ssl_deploy": "腾讯云 - 通过 SSL 证书服务创建部署任务", "provider.tencentcloud.vod": "腾讯云 - 云点播 VOD", "provider.tencentcloud.waf": "腾讯云 - Web 应用防火墙 WAF", @@ -106,6 +110,7 @@ "provider.category.loadbalance": "负载均衡", "provider.category.firewall": "防火墙", "provider.category.av": "音视频", - "provider.category.website": "网站", + "provider.category.serverless": "Serverless", + "provider.category.website": "网站托管", "provider.category.other": "其他" } diff --git a/ui/src/i18n/locales/zh/nls.settings.json b/ui/src/i18n/locales/zh/nls.settings.json index c2204d4d..1fcec35d 100644 --- a/ui/src/i18n/locales/zh/nls.settings.json +++ b/ui/src/i18n/locales/zh/nls.settings.json @@ -16,16 +16,16 @@ "settings.password.form.password.errmsg.not_matched": "两次密码不一致", "settings.notification.tab": "消息推送", - "settings.notification.template.card.title": "通知模板", + "settings.notification.template.card.title": "证书过期通知模板(全局)", "settings.notification.template.form.subject.label": "通知主题", "settings.notification.template.form.subject.placeholder": "请输入通知主题", "settings.notification.template.form.subject.extra": "支持的变量(${COUNT}: 即将过期张数)", "settings.notification.template.form.message.label": "通知内容", "settings.notification.template.form.message.placeholder": "请输入通知内容", - "settings.notification.template.form.message.extra": "支持的变量(${COUNT}: 即将过期张数;${DOMAINS}: 域名列表)", + "settings.notification.template.form.message.extra": "过期前 20 天发送通知。支持的变量(${COUNT}: 即将过期张数;${DOMAINS}: 域名列表)", "settings.notification.channels.card.title": "通知渠道", - "settings.notification.channel.enabled.on": "启用", - "settings.notification.channel.enabled.off": "停用", + "settings.notification.channel.switch.on": "启用", + "settings.notification.channel.switch.off": "停用", "settings.notification.push_test.button": "推送测试消息", "settings.notification.push_test.pushed": "已推送", "settings.notification.channel.form.bark_server_url.label": "服务器地址", @@ -44,7 +44,7 @@ "settings.notification.channel.form.email_smtp_host.placeholder": "请输入 SMTP 服务器地址", "settings.notification.channel.form.email_smtp_port.label": "SMTP 服务器端口", "settings.notification.channel.form.email_smtp_port.placeholder": "请输入 SMTP 服务器端口", - "settings.notification.channel.form.email_smtp_tls.label": "TLS/SSL 连接", + "settings.notification.channel.form.email_smtp_tls.label": "SSL/TLS 连接", "settings.notification.channel.form.email_username.label": "用户名", "settings.notification.channel.form.email_username.placeholder": "请输入用户名", "settings.notification.channel.form.email_password.label": "密码", diff --git a/ui/src/i18n/locales/zh/nls.workflow.nodes.json b/ui/src/i18n/locales/zh/nls.workflow.nodes.json index e0e8cab4..2ba9e329 100644 --- a/ui/src/i18n/locales/zh/nls.workflow.nodes.json +++ b/ui/src/i18n/locales/zh/nls.workflow.nodes.json @@ -20,7 +20,7 @@ "workflow_node.start.form.trigger_cron.errmsg.invalid": "请输入正确的 Cron 表达式", "workflow_node.start.form.trigger_cron.tooltip": "五段式表达式,支持使用任意值(即 *)、值列表分隔符(即 ,)、值的范围(即 -)、步骤值(即 /)等四种表达式。时区以服务器设置为准。", "workflow_node.start.form.trigger_cron.extra": "预计最近 5 次执行时间:", - "workflow_node.start.form.trigger_cron.guide": "小贴士:如果你有多个工作流,建议将它们设置为在一天中的多个时间段运行,而非总是在相同的特定时间。

参考链接:
1. Let’s Encrypt 速率限制
2. 为什么我的 Let’s Encrypt (ACME) 客户端启动时间应当随机?", + "workflow_node.start.form.trigger_cron.guide": "小贴士:如果你有多个工作流,建议将它们设置为在一天中的多个时间段运行,而非总是在相同的特定时间。也不要总是设置为每日零时,以免遭遇证书颁发机构的流量高峰。

参考链接:
1. Let’s Encrypt 速率限制
2. 为什么我的 Let’s Encrypt (ACME) 客户端启动时间应当随机?", "workflow_node.apply.label": "申请", "workflow_node.apply.form.domains.label": "域名", @@ -85,11 +85,15 @@ "workflow_node.deploy.form.provider_access.placeholder": "请选择主机提供商授权", "workflow_node.deploy.form.provider_access.tooltip": "用于部署证书,注意与申请阶段所需的 DNS 提供商相区分。", "workflow_node.deploy.form.provider_access.button": "新建", - "workflow_node.deploy.form.provider_access.guide_for_local": "小贴士:由于表单限制,你同样需要为本地部署选择一个授权 —— 即使它是空白的。", + "workflow_node.deploy.form.provider_access.guide_for_local": "小贴士:由于表单限制,你同样需要为本地部署选择一个授权 —— 即使它是空白的。
请注意:如果你使用 Docker 安装 Certimate,“本地部署”将会部署到容器内而非宿主机上。", "workflow_node.deploy.form.certificate.label": "待部署证书", "workflow_node.deploy.form.certificate.placeholder": "请选择待部署证书", "workflow_node.deploy.form.certificate.tooltip": "待部署证书来自之前的申请阶段。如果选项为空请先确保前序节点配置正确。", "workflow_node.deploy.form.params_config.label": "参数设置", + "workflow_node.deploy.form.1panel_console_auto_restart.label": "部署后自动重启面板服务", + "workflow_node.deploy.form.1panel_site_website_id.label": "1Panel 网站 ID", + "workflow_node.deploy.form.1panel_site_website_id.placeholder": "请输入 1Panel 网站 ID", + "workflow_node.deploy.form.1panel_site_website_id.tooltip": "请在 1Panel 管理面板查看。", "workflow_node.deploy.form.aliyun_alb_resource_type.label": "证书替换方式", "workflow_node.deploy.form.aliyun_alb_resource_type.placeholder": "请选择证书替换方式", "workflow_node.deploy.form.aliyun_alb_resource_type.option.loadbalancer.label": "替换指定负载均衡器下的全部 HTTPS/QUIC 监听的证书", @@ -150,6 +154,14 @@ "workflow_node.deploy.form.aliyun_esa_site_id.label": "阿里云 ESA 站点 ID", "workflow_node.deploy.form.aliyun_esa_site_id.placeholder": "请输入阿里云 ESA 站点 ID", "workflow_node.deploy.form.aliyun_esa_site_id.tooltip": "这是什么?请参阅 https://esa.console.aliyun.com/siteManage/list", + "workflow_node.deploy.form.aliyun_fc_region.label": "阿里云 FC 服务地域", + "workflow_node.deploy.form.aliyun_fc_region.placeholder": "请输入阿里云 FC 服务地域(例如:cn-hangzhou)", + "workflow_node.deploy.form.aliyun_fc_region.tooltip": "这是什么?请参阅 https://help.aliyun.com/zh/functioncompute/fc-3-0/product-overview/supported-regions", + "workflow_node.deploy.form.aliyun_fc_service_version.label": "阿里云 FC 服务版本", + "workflow_node.deploy.form.aliyun_fc_service_version.placeholder": "请选择阿里云 FC 服务版本", + "workflow_node.deploy.form.aliyun_fc_domain.label": "阿里云 FC 自定义域名", + "workflow_node.deploy.form.aliyun_fc_domain.placeholder": "请输入阿里云 FC 自定义域名", + "workflow_node.deploy.form.aliyun_fc_domain.tooltip": "这是什么?请参阅 see https://fcnext.console.aliyun.com/", "workflow_node.deploy.form.aliyun_live_region.label": "阿里云视频直播服务地域", "workflow_node.deploy.form.aliyun_live_region.placeholder": "请输入阿里云视频直播服务地域(例如:cn-hangzhou)", "workflow_node.deploy.form.aliyun_live_region.tooltip": "这是什么?请参阅 https://help.aliyun.com/zh/live/product-overview/supported-regions", @@ -341,9 +353,9 @@ "workflow_node.deploy.form.local_shell_env.option.sh.label": "POSIX Bash(Linux / macOS)", "workflow_node.deploy.form.local_shell_env.option.cmd.label": "CMD(Windows)", "workflow_node.deploy.form.local_shell_env.option.powershell.label": "PowerShell(Windows)", - "workflow_node.deploy.form.local_pre_command.label": "前置命令", + "workflow_node.deploy.form.local_pre_command.label": "前置命令(可选)", "workflow_node.deploy.form.local_pre_command.placeholder": "请输入保存文件前执行的命令", - "workflow_node.deploy.form.local_post_command.label": "后置命令", + "workflow_node.deploy.form.local_post_command.label": "后置命令(可选)", "workflow_node.deploy.form.local_post_command.placeholder": "请输入保存文件后执行的命令", "workflow_node.deploy.form.local_preset_scripts.button": "使用预设脚本", "workflow_node.deploy.form.local_preset_scripts.option.reload_nginx.label": "POSIX Bash - 重启 nginx 进程", @@ -388,9 +400,9 @@ "workflow_node.deploy.form.ssh_jks_storepass.tooltip": "这是什么?请参阅 https://docs.oracle.com/cd/E19509-01/820-3503/ggfen/index.html", "workflow_node.deploy.form.ssh_shell_env.label": "命令执行环境", "workflow_node.deploy.form.ssh_shell_env.value": "POSIX Bash(Linux / macOS)", - "workflow_node.deploy.form.ssh_pre_command.label": "前置命令", + "workflow_node.deploy.form.ssh_pre_command.label": "前置命令(可选)", "workflow_node.deploy.form.ssh_pre_command.placeholder": "请输入保存文件前执行的命令", - "workflow_node.deploy.form.ssh_post_command.label": "后置命令", + "workflow_node.deploy.form.ssh_post_command.label": "后置命令(可选)", "workflow_node.deploy.form.ssh_post_command.placeholder": "请输入保存文件后执行的命令", "workflow_node.deploy.form.ssh_preset_scripts.button": "使用预设脚本", "workflow_node.deploy.form.ssh_preset_scripts.option.reload_nginx.label": "POSIX Bash - 重启 nginx 进程", @@ -441,6 +453,12 @@ "workflow_node.deploy.form.tencentcloud_eo_domain.label": "腾讯云 EdgeOne 加速域名", "workflow_node.deploy.form.tencentcloud_eo_domain.placeholder": "请输入腾讯云 EdgeOne 加速域名", "workflow_node.deploy.form.tencentcloud_eo_domain.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/edgeone", + "workflow_node.deploy.form.tencentcloud_scf_region.label": "腾讯云 SCF 产品地域", + "workflow_node.deploy.form.tencentcloud_scf_region.placeholder": "输入腾讯云 SCF 产品地域(例如:ap-guangzhou)", + "workflow_node.deploy.form.tencentcloud_scf_region.tooltip": "这是什么?请参阅 https://cloud.tencent.com/document/product/583/17299", + "workflow_node.deploy.form.tencentcloud_scf_domain.label": "腾讯云 SCF 自定义域名", + "workflow_node.deploy.form.tencentcloud_scf_domain.placeholder": "输入腾讯云 SCF 自定义域名", + "workflow_node.deploy.form.tencentcloud_scf_domain.tooltip": "这是什么?请参阅 https://console.tencentcloud.com/scf", "workflow_node.deploy.form.tencentcloud_ssl_deploy.guide": "小贴士:由于腾讯云证书部署任务是异步的,此节点若执行成功仅代表已创建部署任务,实际部署结果需要你自行前往腾讯云控制台查询。", "workflow_node.deploy.form.tencentcloud_ssl_deploy_region.label": "腾讯云云产品地域", "workflow_node.deploy.form.tencentcloud_ssl_deploy_region.placeholder": "请输入腾讯云云产品地域(例如:ap-guangzhou)", @@ -529,8 +547,8 @@ "workflow_node.deploy.form.skip_on_last_succeeded.label": "重复部署", "workflow_node.deploy.form.skip_on_last_succeeded.prefix": "当上次部署已成功时", "workflow_node.deploy.form.skip_on_last_succeeded.suffix": "重新部署。", - "workflow_node.deploy.form.skip_on_last_succeeded.enabled.on": "跳过", - "workflow_node.deploy.form.skip_on_last_succeeded.enabled.off": "不跳过", + "workflow_node.deploy.form.skip_on_last_succeeded.switch.on": "跳过", + "workflow_node.deploy.form.skip_on_last_succeeded.switch.off": "不跳过", "workflow_node.notify.label": "通知", "workflow_node.notify.form.subject.label": "通知主题", diff --git a/ui/src/pages/dashboard/Dashboard.tsx b/ui/src/pages/dashboard/Dashboard.tsx index 9ec84efb..ea7a21cb 100644 --- a/ui/src/pages/dashboard/Dashboard.tsx +++ b/ui/src/pages/dashboard/Dashboard.tsx @@ -310,7 +310,7 @@ const StatisticCard = ({ onClick?: () => void; }) => { return ( - + {icon} ((set, get) => ({ }, getWorkflowOuptutBeforeId: (nodeId: string, type: string) => { - return getWorkflowOutputBeforeId(get().workflow.draft as WorkflowNode, nodeId, type); + return getOutputBeforeNodeId(get().workflow.draft as WorkflowNode, nodeId, type); }, })); diff --git a/ui/src/utils/cron.ts b/ui/src/utils/cron.ts index 79a94ddc..46d806e3 100644 --- a/ui/src/utils/cron.ts +++ b/ui/src/utils/cron.ts @@ -1,8 +1,8 @@ -import { parseExpression } from "cron-parser"; +import { CronExpressionParser } from "cron-parser"; export const validCronExpression = (expr: string): boolean => { try { - parseExpression(expr); + CronExpressionParser.parse(expr); if (expr.trim().split(" ").length !== 5) return false; // pocketbase 后端仅支持五段式的表达式 return true; @@ -15,12 +15,7 @@ export const getNextCronExecutions = (expr: string, times = 1): Date[] => { if (!validCronExpression(expr)) return []; const now = new Date(); - const cron = parseExpression(expr, { currentDate: now, iterator: true }); + const cron = CronExpressionParser.parse(expr, { currentDate: now }); - const result: Date[] = []; - for (let i = 0; i < times; i++) { - const next = cron.next(); - result.push(next.value.toDate()); - } - return result; + return cron.take(times).map((date) => date.toDate()); };