mirror of
https://github.com/usual2970/certimate.git
synced 2025-06-08 05:29:51 +00:00
Replace the OSS deployment api
This commit is contained in:
parent
2ed94bf509
commit
5b30fc8aba
2
go.mod
2
go.mod
@ -5,11 +5,11 @@ go 1.22.0
|
||||
toolchain go1.23.2
|
||||
|
||||
require (
|
||||
github.com/alibabacloud-go/cas-20200407/v2 v2.3.0
|
||||
github.com/alibabacloud-go/cdn-20180510/v5 v5.0.0
|
||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.9
|
||||
github.com/alibabacloud-go/tea v1.2.2
|
||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.6
|
||||
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
|
||||
github.com/go-acme/lego/v4 v4.19.2
|
||||
github.com/gojek/heimdall/v7 v7.0.3
|
||||
github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61
|
||||
|
5
go.sum
5
go.sum
@ -31,12 +31,9 @@ github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3
|
||||
github.com/alex-ant/gomath v0.0.0-20160516115720-89013a210a82/go.mod h1:nLnM0KdK1CmygvjpDUO6m1TjSsiQtL61juhNsvV/JVI=
|
||||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 h1:iC9YFYKDGEy3n/FtqJnOkZsene9olVspKmkX5A2YBEo=
|
||||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc=
|
||||
github.com/alibabacloud-go/cas-20200407/v2 v2.3.0 h1:nOrp0n2nFZiYN0wIG7S26YVVaMMzOBkX9GJqUvYnGeE=
|
||||
github.com/alibabacloud-go/cas-20200407/v2 v2.3.0/go.mod h1:yzkgdLANANu/v56k0ptslGl++JJL4Op1V09HTavfoCo=
|
||||
github.com/alibabacloud-go/cdn-20180510/v5 v5.0.0 h1:yTKngw4rBR3hdpoo/uCyBffYXfPfjNjlaDL8nTYUIds=
|
||||
github.com/alibabacloud-go/cdn-20180510/v5 v5.0.0/go.mod h1:HxQrwVKBx3/6bIwmdDcpqBpSQt2tpi/j4LfEhl+QFPk=
|
||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.0/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ=
|
||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.6/go.mod h1:CzQnh+94WDnJOnKZH5YRyouL+OOcdBnXY5VWAf0McgI=
|
||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.8/go.mod h1:CzQnh+94WDnJOnKZH5YRyouL+OOcdBnXY5VWAf0McgI=
|
||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.9 h1:fxMCrZatZfXq5nLcgkmWBXmU3FLC1OR+m/SqVtMqflk=
|
||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.9/go.mod h1:bb+Io8Sn2RuM3/Rpme6ll86jMyFSrD1bxeV/+v61KeU=
|
||||
@ -82,6 +79,8 @@ github.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzY
|
||||
github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.63.15 h1:r2uwBUQhLhcPzaWz9tRJqc8MjYwHb+oF2+Q6467BF14=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.63.15/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
|
||||
github.com/aliyun/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.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=
|
||||
github.com/aliyun/credentials-go v1.3.1 h1:uq/0v7kWrxmoLGpqjx7vtQ/s03f0zR//0br/xWDTE28=
|
||||
github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0=
|
||||
|
@ -1,23 +1,16 @@
|
||||
package deployer
|
||||
|
||||
import (
|
||||
"certimate/internal/applicant"
|
||||
"certimate/internal/domain"
|
||||
"certimate/internal/utils/rand"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
cas20200407 "github.com/alibabacloud-go/cas-20200407/v2/client"
|
||||
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
||||
util "github.com/alibabacloud-go/tea-utils/v2/service"
|
||||
"github.com/alibabacloud-go/tea/tea"
|
||||
"github.com/aliyun/aliyun-oss-go-sdk/oss"
|
||||
)
|
||||
|
||||
type aliyun struct {
|
||||
client *cas20200407.Client
|
||||
client *oss.Client
|
||||
option *DeployerOption
|
||||
infos []string
|
||||
}
|
||||
@ -47,160 +40,31 @@ func (a *aliyun) GetInfo() []string {
|
||||
}
|
||||
|
||||
func (a *aliyun) Deploy(ctx context.Context) error {
|
||||
|
||||
// 查询有没有对应的资源
|
||||
resource, err := a.resource()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.infos = append(a.infos, toStr("查询对应的资源", resource))
|
||||
|
||||
// 查询有没有对应的联系人
|
||||
contacts, err := a.contacts()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.infos = append(a.infos, toStr("查询联系人", contacts))
|
||||
|
||||
// 上传证书
|
||||
certId, err := a.uploadCert(&a.option.Certificate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.infos = append(a.infos, toStr("上传证书", certId))
|
||||
|
||||
// 部署证书
|
||||
jobId, err := a.deploy(resource, certId, contacts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.infos = append(a.infos, toStr("创建部署证书任务", jobId))
|
||||
|
||||
// 等待部署成功
|
||||
err = a.updateDeployStatus(*jobId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 部署成功后删除旧的证书
|
||||
a.deleteCert(resource)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *aliyun) updateDeployStatus(jobId int64) error {
|
||||
// 查询部署状态
|
||||
req := &cas20200407.UpdateDeploymentJobStatusRequest{
|
||||
JobId: tea.Int64(jobId),
|
||||
}
|
||||
|
||||
resp, err := a.client.UpdateDeploymentJobStatus(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.infos = append(a.infos, toStr("查询对应的资源", resp))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *aliyun) deleteCert(resource *cas20200407.ListCloudResourcesResponseBodyData) error {
|
||||
// 查询有没有对应的资源
|
||||
if resource.CertId == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 删除证书
|
||||
_, err := a.client.DeleteUserCertificate(&cas20200407.DeleteUserCertificateRequest{
|
||||
CertId: resource.CertId,
|
||||
err := a.client.PutBucketCnameWithCertificate(getDeployString(a.option.DeployConfig, "bucket"), oss.PutBucketCname{
|
||||
Cname: getDeployString(a.option.DeployConfig, "domain"),
|
||||
CertificateConfiguration: &oss.CertificateConfiguration{
|
||||
Certificate: a.option.Certificate.Certificate,
|
||||
PrivateKey: a.option.Certificate.PrivateKey,
|
||||
Force: true,
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("deploy aliyun oss error: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (a *aliyun) contacts() ([]*cas20200407.ListContactResponseBodyContactList, error) {
|
||||
listContactRequest := &cas20200407.ListContactRequest{}
|
||||
runtime := &util.RuntimeOptions{}
|
||||
|
||||
resp, err := a.client.ListContactWithOptions(listContactRequest, runtime)
|
||||
func (a *aliyun) createClient(accessKeyId, accessKeySecret string) (*oss.Client, error) {
|
||||
client, err := oss.New(
|
||||
getDeployString(a.option.DeployConfig, "endpoint"),
|
||||
accessKeyId,
|
||||
accessKeySecret,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("create aliyun client error: %w", err)
|
||||
}
|
||||
if resp.Body.TotalCount == nil {
|
||||
return nil, errors.New("no contact found")
|
||||
}
|
||||
|
||||
return resp.Body.ContactList, nil
|
||||
}
|
||||
|
||||
func (a *aliyun) deploy(resource *cas20200407.ListCloudResourcesResponseBodyData, certId int64, contacts []*cas20200407.ListContactResponseBodyContactList) (*int64, error) {
|
||||
contactIds := make([]string, 0, len(contacts))
|
||||
for _, contact := range contacts {
|
||||
contactIds = append(contactIds, fmt.Sprintf("%d", *contact.ContactId))
|
||||
}
|
||||
// 部署证书
|
||||
createCloudResourceRequest := &cas20200407.CreateDeploymentJobRequest{
|
||||
CertIds: tea.String(fmt.Sprintf("%d", certId)),
|
||||
Name: tea.String(a.option.Domain + rand.RandStr(6)),
|
||||
JobType: tea.String("user"),
|
||||
ResourceIds: tea.String(fmt.Sprintf("%d", *resource.Id)),
|
||||
ContactIds: tea.String(strings.Join(contactIds, ",")),
|
||||
}
|
||||
runtime := &util.RuntimeOptions{}
|
||||
|
||||
resp, err := a.client.CreateDeploymentJobWithOptions(createCloudResourceRequest, runtime)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp.Body.JobId, nil
|
||||
}
|
||||
|
||||
func (a *aliyun) uploadCert(cert *applicant.Certificate) (int64, error) {
|
||||
uploadUserCertificateRequest := &cas20200407.UploadUserCertificateRequest{
|
||||
Cert: &cert.Certificate,
|
||||
Key: &cert.PrivateKey,
|
||||
Name: tea.String(a.option.Domain + rand.RandStr(6)),
|
||||
}
|
||||
runtime := &util.RuntimeOptions{}
|
||||
|
||||
resp, err := a.client.UploadUserCertificateWithOptions(uploadUserCertificateRequest, runtime)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return *resp.Body.CertId, nil
|
||||
}
|
||||
|
||||
func (a *aliyun) createClient(accessKeyId, accessKeySecret string) (_result *cas20200407.Client, _err error) {
|
||||
config := &openapi.Config{
|
||||
AccessKeyId: tea.String(accessKeyId),
|
||||
AccessKeySecret: tea.String(accessKeySecret),
|
||||
}
|
||||
config.Endpoint = tea.String("cas.aliyuncs.com")
|
||||
_result = &cas20200407.Client{}
|
||||
_result, _err = cas20200407.NewClient(config)
|
||||
return _result, _err
|
||||
}
|
||||
|
||||
func (a *aliyun) resource() (*cas20200407.ListCloudResourcesResponseBodyData, error) {
|
||||
|
||||
listCloudResourcesRequest := &cas20200407.ListCloudResourcesRequest{
|
||||
CloudProduct: tea.String(a.option.Product),
|
||||
Keyword: tea.String(getDeployString(a.option.DeployConfig, "domain")),
|
||||
}
|
||||
|
||||
resp, err := a.client.ListCloudResources(listCloudResourcesRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if *resp.Body.Total == 0 {
|
||||
return nil, errors.New("no resource found")
|
||||
}
|
||||
|
||||
return resp.Body.Data[0], nil
|
||||
return client, nil
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
2
ui/dist/index.html
vendored
2
ui/dist/index.html
vendored
@ -5,7 +5,7 @@
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Certimate - Your Trusted SSL Automation Partner</title>
|
||||
<script type="module" crossorigin src="/assets/index-DbwFzZm1.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-DvxNVikK.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-CWUb5Xuf.css">
|
||||
</head>
|
||||
<body class="bg-background">
|
||||
|
@ -479,7 +479,7 @@ const DeployEdit = ({ type }: DeployEditProps) => {
|
||||
case "dcdn":
|
||||
return <DeployCDN />;
|
||||
case "oss":
|
||||
return <DeployCDN />;
|
||||
return <DeployOSS />;
|
||||
case "webhook":
|
||||
return <DeployWebhook />;
|
||||
default:
|
||||
@ -659,6 +659,158 @@ const DeployCDN = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const DeployOSS = () => {
|
||||
const { deploy: data, setDeploy, error, setError } = useDeployEditContext();
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
setError({});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const resp = domainSchema.safeParse(data.config?.domain);
|
||||
if (!resp.success) {
|
||||
setError({
|
||||
...error,
|
||||
domain: JSON.parse(resp.error.message)[0].message,
|
||||
});
|
||||
} else {
|
||||
setError({
|
||||
...error,
|
||||
domain: "",
|
||||
});
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
useEffect(() => {
|
||||
const bucketResp = bucketSchema.safeParse(data.config?.domain);
|
||||
if (!bucketResp.success) {
|
||||
setError({
|
||||
...error,
|
||||
bucket: JSON.parse(bucketResp.error.message)[0].message,
|
||||
});
|
||||
} else {
|
||||
setError({
|
||||
...error,
|
||||
bucket: "",
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!data.id) {
|
||||
setDeploy({
|
||||
...data,
|
||||
config: {
|
||||
endpoint: "oss-cn-hangzhou.aliyuncs.com",
|
||||
bucket: "",
|
||||
domain: "",
|
||||
},
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
const domainSchema = z
|
||||
.string()
|
||||
.regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
|
||||
message: t("domain.not.empty.verify.message"),
|
||||
});
|
||||
|
||||
const bucketSchema = z.string().min(1, {
|
||||
message: t("deployment.access.oss.bucket.not.empty"),
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="flex flex-col space-y-2">
|
||||
<div>
|
||||
<Label>{t("deployment.access.oss.endpoint")}</Label>
|
||||
|
||||
<Input
|
||||
className="w-full mt-1"
|
||||
value={data?.config?.endpoint}
|
||||
onChange={(e) => {
|
||||
const temp = e.target.value;
|
||||
|
||||
const newData = produce(data, (draft) => {
|
||||
if (!draft.config) {
|
||||
draft.config = {};
|
||||
}
|
||||
draft.config.endpoint = temp;
|
||||
});
|
||||
setDeploy(newData);
|
||||
}}
|
||||
/>
|
||||
<div className="text-red-600 text-sm mt-1">{error?.endpoint}</div>
|
||||
|
||||
<Label>{t("deployment.access.oss.bucket")}</Label>
|
||||
<Input
|
||||
placeholder={t("deployment.access.oss.bucket.not.empty")}
|
||||
className="w-full mt-1"
|
||||
value={data?.config?.bucket}
|
||||
onChange={(e) => {
|
||||
const temp = e.target.value;
|
||||
|
||||
const resp = bucketSchema.safeParse(temp);
|
||||
if (!resp.success) {
|
||||
setError({
|
||||
...error,
|
||||
bucket: JSON.parse(resp.error.message)[0].message,
|
||||
});
|
||||
} else {
|
||||
setError({
|
||||
...error,
|
||||
bucket: "",
|
||||
});
|
||||
}
|
||||
|
||||
const newData = produce(data, (draft) => {
|
||||
if (!draft.config) {
|
||||
draft.config = {};
|
||||
}
|
||||
draft.config.bucket = temp;
|
||||
});
|
||||
setDeploy(newData);
|
||||
}}
|
||||
/>
|
||||
<div className="text-red-600 text-sm mt-1">{error?.bucket}</div>
|
||||
|
||||
<Label>{t("deployment.access.cdn.deploy.to.domain")}</Label>
|
||||
<Input
|
||||
placeholder={t("deployment.access.cdn.deploy.to.domain")}
|
||||
className="w-full mt-1"
|
||||
value={data?.config?.domain}
|
||||
onChange={(e) => {
|
||||
const temp = e.target.value;
|
||||
|
||||
const resp = domainSchema.safeParse(temp);
|
||||
if (!resp.success) {
|
||||
setError({
|
||||
...error,
|
||||
domain: JSON.parse(resp.error.message)[0].message,
|
||||
});
|
||||
} else {
|
||||
setError({
|
||||
...error,
|
||||
domain: "",
|
||||
});
|
||||
}
|
||||
|
||||
const newData = produce(data, (draft) => {
|
||||
if (!draft.config) {
|
||||
draft.config = {};
|
||||
}
|
||||
draft.config.domain = temp;
|
||||
});
|
||||
setDeploy(newData);
|
||||
}}
|
||||
/>
|
||||
<div className="text-red-600 text-sm mt-1">{error?.domain}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const DeployWebhook = () => {
|
||||
const { deploy: data, setDeploy } = useDeployEditContext();
|
||||
|
||||
|
@ -239,5 +239,9 @@
|
||||
"deployment.not.added": "Deployment not added yet",
|
||||
"deployment.access.type": "Access Type",
|
||||
"deployment.access.config": "Access Configuration",
|
||||
"deployment.access.cdn.deploy.to.domain": "Deploy to domain"
|
||||
"deployment.access.cdn.deploy.to.domain": "Deploy to domain",
|
||||
|
||||
"deployment.access.oss.bucket": "Bucket",
|
||||
"deployment.access.oss.bucket.not.empty": "Please enter Bucket",
|
||||
"deployment.access.oss.endpoint": "Endpoint"
|
||||
}
|
||||
|
@ -239,5 +239,9 @@
|
||||
"deployment.not.added": "暂无部署配置,请添加后开始部署证书吧",
|
||||
"deployment.access.type": "授权类型",
|
||||
"deployment.access.config": "授权配置",
|
||||
"deployment.access.cdn.deploy.to.domain": "部署到域名"
|
||||
"deployment.access.cdn.deploy.to.domain": "部署到域名",
|
||||
|
||||
"deployment.access.oss.bucket": "Bucket",
|
||||
"deployment.access.oss.bucket.not.empty": "请输入 Bucket",
|
||||
"deployment.access.oss.endpoint": "Endpoint"
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user