mirror of
https://github.com/woodchen-ink/certimate.git
synced 2025-07-18 09:21:56 +08:00
feat: rename domain
to subjectAltNames
This commit is contained in:
parent
5387c373e0
commit
9246878d0e
@ -54,8 +54,8 @@ type Certificate struct {
|
||||
}
|
||||
|
||||
type ApplyOption struct {
|
||||
Domains string `json:"domains"`
|
||||
ContactEmail string `json:"contactEmail"`
|
||||
SubjectAltNames string `json:"subjectAltNames"`
|
||||
AccessConfig string `json:"accessConfig"`
|
||||
KeyAlgorithm string `json:"keyAlgorithm"`
|
||||
Nameservers string `json:"nameservers"`
|
||||
@ -132,8 +132,8 @@ func GetWithApplyNode(node *domain.WorkflowNode) (Applicant, error) {
|
||||
}
|
||||
|
||||
applyConfig := &ApplyOption{
|
||||
Domains: node.GetConfigString("domains"),
|
||||
ContactEmail: node.GetConfigString("contactEmail"),
|
||||
SubjectAltNames: node.GetConfigString("subjectAltNames"),
|
||||
AccessConfig: access.Config,
|
||||
KeyAlgorithm: node.GetConfigString("keyAlgorithm"),
|
||||
Nameservers: node.GetConfigString("nameservers"),
|
||||
@ -243,7 +243,7 @@ func apply(option *ApplyOption, provider challenge.Provider) (*Certificate, erro
|
||||
myUser.Registration = reg
|
||||
}
|
||||
|
||||
domains := strings.Split(option.SubjectAltNames, ";")
|
||||
domains := strings.Split(option.Domains, ";")
|
||||
request := certificate.ObtainRequest{
|
||||
Domains: domains,
|
||||
Bundle: true,
|
||||
|
@ -83,7 +83,7 @@ func buildMsg(records []domain.Certificate) *domain.NotifyMessage {
|
||||
domains := make([]string, count)
|
||||
|
||||
for i, record := range records {
|
||||
domains[i] = record.SAN
|
||||
domains[i] = record.SubjectAltNames
|
||||
}
|
||||
|
||||
countStr := strconv.Itoa(count)
|
||||
|
@ -4,13 +4,10 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/pocketbase/pocketbase/models"
|
||||
|
||||
"github.com/usual2970/certimate/internal/applicant"
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||
"github.com/usual2970/certimate/internal/pkg/core/logger"
|
||||
"github.com/usual2970/certimate/internal/repository"
|
||||
)
|
||||
|
||||
/*
|
||||
@ -47,8 +44,8 @@ const (
|
||||
)
|
||||
|
||||
type DeployerOption struct {
|
||||
DomainId string `json:"domainId"`
|
||||
Domain string `json:"domain"`
|
||||
NodeId string `json:"nodeId"`
|
||||
Domains string `json:"domains"`
|
||||
AccessConfig string `json:"accessConfig"`
|
||||
AccessRecord *domain.Access `json:"-"`
|
||||
DeployConfig domain.DeployConfig `json:"deployConfig"`
|
||||
@ -62,66 +59,7 @@ type Deployer interface {
|
||||
GetID() string
|
||||
}
|
||||
|
||||
func Gets(record *models.Record, cert *applicant.Certificate) ([]Deployer, error) {
|
||||
rs := make([]Deployer, 0)
|
||||
if record.GetString("deployConfig") == "" {
|
||||
return rs, nil
|
||||
}
|
||||
|
||||
deployConfigs := make([]domain.DeployConfig, 0)
|
||||
|
||||
err := record.UnmarshalJSONField("deployConfig", &deployConfigs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("解析部署配置失败: %w", err)
|
||||
}
|
||||
|
||||
if len(deployConfigs) == 0 {
|
||||
return rs, nil
|
||||
}
|
||||
|
||||
for _, deployConfig := range deployConfigs {
|
||||
deployer, err := newWithDeployConfig(record, cert, deployConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rs = append(rs, deployer)
|
||||
}
|
||||
|
||||
return rs, nil
|
||||
}
|
||||
|
||||
func GetWithTypeAndOption(deployType string, option *DeployerOption) (Deployer, error) {
|
||||
return newWithTypeAndOption(deployType, option)
|
||||
}
|
||||
|
||||
func newWithDeployConfig(record *models.Record, cert *applicant.Certificate, deployConfig domain.DeployConfig) (Deployer, error) {
|
||||
accessRepo := repository.NewAccessRepository()
|
||||
access, err := accessRepo.GetById(context.Background(), deployConfig.ProviderAccessId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("获取access失败:%w", err)
|
||||
}
|
||||
|
||||
option := &DeployerOption{
|
||||
DomainId: record.Id,
|
||||
Domain: record.GetString("domain"),
|
||||
AccessConfig: access.Config,
|
||||
AccessRecord: access,
|
||||
DeployConfig: deployConfig,
|
||||
}
|
||||
if cert != nil {
|
||||
option.Certificate = *cert
|
||||
} else {
|
||||
option.Certificate = applicant.Certificate{
|
||||
Certificate: record.GetString("certificate"),
|
||||
PrivateKey: record.GetString("privateKey"),
|
||||
}
|
||||
}
|
||||
|
||||
return newWithTypeAndOption(deployConfig.Provider, option)
|
||||
}
|
||||
|
||||
func newWithTypeAndOption(deployType string, option *DeployerOption) (Deployer, error) {
|
||||
deployer, logger, err := createDeployer(deployType, option.AccessRecord.Config, option.DeployConfig.NodeConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -6,7 +6,7 @@ var ValidityDuration = time.Hour * 24 * 10
|
||||
|
||||
type Certificate struct {
|
||||
Meta
|
||||
SAN string `json:"san" db:"san"`
|
||||
SubjectAltNames string `json:"san" db:"san"`
|
||||
Certificate string `json:"certificate" db:"certificate"`
|
||||
PrivateKey string `json:"privateKey" db:"privateKey"`
|
||||
IssuerCertificate string `json:"issuerCertificate" db:"issuerCertificate"`
|
||||
|
@ -79,7 +79,7 @@ func (w *WorkflowOutputRepository) GetCertificate(ctx context.Context, nodeId st
|
||||
Certificate: record.GetString("certificate"),
|
||||
PrivateKey: record.GetString("privateKey"),
|
||||
IssuerCertificate: record.GetString("issuerCertificate"),
|
||||
SAN: record.GetString("san"),
|
||||
SubjectAltNames: record.GetString("san"),
|
||||
WorkflowOutputId: record.GetString("output"),
|
||||
ExpireAt: record.GetDateTime("expireAt").Time(),
|
||||
CertUrl: record.GetString("certUrl"),
|
||||
@ -131,7 +131,7 @@ func (w *WorkflowOutputRepository) Save(ctx context.Context, output *domain.Work
|
||||
certRecord.Set("certificate", certificate.Certificate)
|
||||
certRecord.Set("privateKey", certificate.PrivateKey)
|
||||
certRecord.Set("issuerCertificate", certificate.IssuerCertificate)
|
||||
certRecord.Set("san", certificate.SAN)
|
||||
certRecord.Set("san", certificate.SubjectAltNames)
|
||||
certRecord.Set("output", certificate.WorkflowOutputId)
|
||||
certRecord.Set("expireAt", certificate.ExpireAt)
|
||||
certRecord.Set("certUrl", certificate.CertUrl)
|
||||
|
@ -96,7 +96,7 @@ func (a *applyNode) Run(ctx context.Context) error {
|
||||
}
|
||||
|
||||
certificateRecord := &domain.Certificate{
|
||||
SAN: strings.Join(cert.DNSNames, ";"),
|
||||
SubjectAltNames: strings.Join(cert.DNSNames, ";"),
|
||||
Certificate: certificate.Certificate,
|
||||
PrivateKey: certificate.PrivateKey,
|
||||
IssuerCertificate: certificate.IssuerCertificate,
|
||||
|
@ -66,8 +66,8 @@ func (d *deployNode) Run(ctx context.Context) error {
|
||||
}
|
||||
|
||||
option := &deployer.DeployerOption{
|
||||
DomainId: d.node.Id,
|
||||
Domain: cert.SAN,
|
||||
NodeId: d.node.Id,
|
||||
Domains: cert.SubjectAltNames,
|
||||
AccessConfig: access.Config,
|
||||
AccessRecord: access,
|
||||
Certificate: applicant.Certificate{
|
||||
|
@ -6,7 +6,15 @@ import { produce } from "immer";
|
||||
import Show from "@/components/Show";
|
||||
import { deployProvidersMap } from "@/domain/provider";
|
||||
import { notifyChannelsMap } from "@/domain/settings";
|
||||
import { WORKFLOW_TRIGGERS, type WorkflowNode, WorkflowNodeType } from "@/domain/workflow";
|
||||
import {
|
||||
WORKFLOW_TRIGGERS,
|
||||
type WorkflowNode,
|
||||
type WorkflowNodeConfigAsApply,
|
||||
type WorkflowNodeConfigAsDeploy,
|
||||
type WorkflowNodeConfigAsNotify,
|
||||
type WorkflowNodeConfigAsStart,
|
||||
WorkflowNodeType,
|
||||
} from "@/domain/workflow";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
|
||||
@ -32,28 +40,31 @@ const WorkflowElement = ({ node, disabled }: NodeProps) => {
|
||||
|
||||
switch (node.type) {
|
||||
case WorkflowNodeType.Start: {
|
||||
const config = (node.config as WorkflowNodeConfigAsStart) ?? {};
|
||||
return (
|
||||
<div className="flex items-center justify-between space-x-2">
|
||||
<Typography.Text className="truncate">
|
||||
{node.config?.trigger === WORKFLOW_TRIGGERS.AUTO
|
||||
{config.trigger === WORKFLOW_TRIGGERS.AUTO
|
||||
? t("workflow.props.trigger.auto")
|
||||
: node.config?.trigger === WORKFLOW_TRIGGERS.MANUAL
|
||||
: config.trigger === WORKFLOW_TRIGGERS.MANUAL
|
||||
? t("workflow.props.trigger.manual")
|
||||
: " "}
|
||||
</Typography.Text>
|
||||
<Typography.Text className="truncate" type="secondary">
|
||||
{node.config?.trigger === WORKFLOW_TRIGGERS.AUTO ? (node.config?.triggerCron as string) : ""}
|
||||
{config.trigger === WORKFLOW_TRIGGERS.AUTO ? config.triggerCron : ""}
|
||||
</Typography.Text>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
case WorkflowNodeType.Apply: {
|
||||
return <Typography.Text className="truncate">{(node.config?.domain as string) || " "}</Typography.Text>;
|
||||
const config = (node.config as WorkflowNodeConfigAsApply) ?? {};
|
||||
return <Typography.Text className="truncate">{config.domains || " "}</Typography.Text>;
|
||||
}
|
||||
|
||||
case WorkflowNodeType.Deploy: {
|
||||
const provider = deployProvidersMap.get(node.config?.provider as string);
|
||||
const config = (node.config as WorkflowNodeConfigAsDeploy) ?? {};
|
||||
const provider = deployProvidersMap.get(config.provider);
|
||||
return (
|
||||
<Space>
|
||||
<Avatar src={provider?.icon} size="small" />
|
||||
@ -63,7 +74,8 @@ const WorkflowElement = ({ node, disabled }: NodeProps) => {
|
||||
}
|
||||
|
||||
case WorkflowNodeType.Notify: {
|
||||
const channel = notifyChannelsMap.get(node.config?.channel as string);
|
||||
const config = (node.config as WorkflowNodeConfigAsNotify) ?? {};
|
||||
const channel = notifyChannelsMap.get(config.channel as string);
|
||||
return (
|
||||
<div className="flex items-center justify-between space-x-2">
|
||||
<Typography.Text className="truncate">{t(channel?.name ?? " ")}</Typography.Text>
|
||||
|
@ -12,7 +12,7 @@ import MultipleInput from "@/components/MultipleInput";
|
||||
import AccessEditModal from "@/components/access/AccessEditModal";
|
||||
import AccessSelect from "@/components/access/AccessSelect";
|
||||
import { ACCESS_USAGES, accessProvidersMap } from "@/domain/provider";
|
||||
import { type WorkflowApplyNodeConfig, type WorkflowNode } from "@/domain/workflow";
|
||||
import { type WorkflowNode, type WorkflowNodeConfigAsApply } from "@/domain/workflow";
|
||||
import { useAntdForm, useZustandShallowSelector } from "@/hooks";
|
||||
import { useAccessesStore } from "@/stores/access";
|
||||
import { useContactEmailsStore } from "@/stores/contact";
|
||||
@ -26,7 +26,7 @@ export type ApplyNodeFormProps = {
|
||||
|
||||
const MULTIPLE_INPUT_DELIMITER = ";";
|
||||
|
||||
const initFormModel = (): Partial<WorkflowApplyNodeConfig> => {
|
||||
const initFormModel = (): Partial<WorkflowNodeConfigAsApply> => {
|
||||
return {
|
||||
keyAlgorithm: "RSA2048",
|
||||
propagationTimeout: 60,
|
||||
@ -43,12 +43,12 @@ const ApplyNodeForm = ({ node }: ApplyNodeFormProps) => {
|
||||
const { hidePanel } = usePanel();
|
||||
|
||||
const formSchema = z.object({
|
||||
domain: z.string({ message: t("workflow_node.apply.form.domains.placeholder") }).refine((v) => {
|
||||
domains: z.string({ message: t("workflow_node.apply.form.domains.placeholder") }).refine((v) => {
|
||||
return String(v)
|
||||
.split(MULTIPLE_INPUT_DELIMITER)
|
||||
.every((e) => validDomainName(e, true));
|
||||
}, t("common.errmsg.domain_invalid")),
|
||||
email: z.string({ message: t("workflow_node.apply.form.contact_email.placeholder") }).email("common.errmsg.email_invalid"),
|
||||
contactEmail: z.string({ message: t("workflow_node.apply.form.contact_email.placeholder") }).email("common.errmsg.email_invalid"),
|
||||
providerAccessId: z
|
||||
.string({ message: t("workflow_node.apply.form.provider_access.placeholder") })
|
||||
.min(1, t("workflow_node.apply.form.provider_access.placeholder")),
|
||||
@ -76,16 +76,16 @@ const ApplyNodeForm = ({ node }: ApplyNodeFormProps) => {
|
||||
formPending,
|
||||
formProps,
|
||||
} = useAntdForm<z.infer<typeof formSchema>>({
|
||||
initialValues: (node?.config as WorkflowApplyNodeConfig) ?? initFormModel(),
|
||||
initialValues: (node?.config as WorkflowNodeConfigAsApply) ?? initFormModel(),
|
||||
onSubmit: async (values) => {
|
||||
await formInst.validateFields();
|
||||
await addEmail(values.email);
|
||||
await addEmail(values.contactEmail);
|
||||
await updateNode(
|
||||
produce(node, (draft) => {
|
||||
draft.config = {
|
||||
provider: accesses.find((e) => e.id === values.providerAccessId)?.provider,
|
||||
...values,
|
||||
} as WorkflowApplyNodeConfig;
|
||||
} as WorkflowNodeConfigAsApply;
|
||||
draft.validated = true;
|
||||
})
|
||||
);
|
||||
@ -93,13 +93,13 @@ const ApplyNodeForm = ({ node }: ApplyNodeFormProps) => {
|
||||
},
|
||||
});
|
||||
|
||||
const [fieldDomains, setFieldDomains] = useState(node?.config?.domain as string);
|
||||
const [fieldDomains, setFieldDomains] = useState(node?.config?.domains as string);
|
||||
const [fieldNameservers, setFieldNameservers] = useState(node?.config?.nameservers as string);
|
||||
|
||||
const handleFieldDomainsChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = e.target.value;
|
||||
setFieldDomains(value);
|
||||
formInst.setFieldValue("domain", value);
|
||||
formInst.setFieldValue("domains", value);
|
||||
};
|
||||
|
||||
const handleFieldNameserversChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
@ -111,7 +111,7 @@ const ApplyNodeForm = ({ node }: ApplyNodeFormProps) => {
|
||||
return (
|
||||
<Form {...formProps} form={formInst} disabled={formPending} layout="vertical">
|
||||
<Form.Item
|
||||
name="domain"
|
||||
name="domains"
|
||||
label={t("workflow_node.apply.form.domains.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.domains.tooltip") }}></span>}
|
||||
@ -132,7 +132,7 @@ const ApplyNodeForm = ({ node }: ApplyNodeFormProps) => {
|
||||
}
|
||||
onFinish={(v) => {
|
||||
setFieldDomains(v);
|
||||
formInst.setFieldValue("domain", v);
|
||||
formInst.setFieldValue("domains", v);
|
||||
}}
|
||||
/>
|
||||
</Space.Compact>
|
||||
|
@ -12,7 +12,7 @@ import AccessSelect from "@/components/access/AccessSelect";
|
||||
import DeployProviderPicker from "@/components/provider/DeployProviderPicker";
|
||||
import DeployProviderSelect from "@/components/provider/DeployProviderSelect";
|
||||
import { ACCESS_USAGES, DEPLOY_PROVIDERS, accessProvidersMap, deployProvidersMap } from "@/domain/provider";
|
||||
import { type WorkflowDeployNodeConfig, type WorkflowNode } from "@/domain/workflow";
|
||||
import { type WorkflowNode, type WorkflowNodeConfigAsDeploy } from "@/domain/workflow";
|
||||
import { useAntdForm, useZustandShallowSelector } from "@/hooks";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { usePanel } from "../PanelProvider";
|
||||
@ -44,7 +44,7 @@ export type DeployFormProps = {
|
||||
node: WorkflowNode;
|
||||
};
|
||||
|
||||
const initFormModel = (): Partial<WorkflowDeployNodeConfig> => {
|
||||
const initFormModel = (): Partial<WorkflowNodeConfigAsDeploy> => {
|
||||
return {};
|
||||
};
|
||||
|
||||
@ -67,7 +67,7 @@ const DeployNodeForm = ({ node }: DeployFormProps) => {
|
||||
formPending,
|
||||
formProps,
|
||||
} = useAntdForm<z.infer<typeof formSchema>>({
|
||||
initialValues: (node?.config as WorkflowDeployNodeConfig) ?? initFormModel(),
|
||||
initialValues: (node?.config as WorkflowNodeConfigAsDeploy) ?? initFormModel(),
|
||||
onSubmit: async (values) => {
|
||||
await formInst.validateFields();
|
||||
await updateNode(
|
||||
|
@ -8,7 +8,7 @@ import { produce } from "immer";
|
||||
import { z } from "zod";
|
||||
|
||||
import { notifyChannelsMap } from "@/domain/settings";
|
||||
import { type WorkflowNode, type WorkflowNotifyNodeConfig } from "@/domain/workflow";
|
||||
import { type WorkflowNode, type WorkflowNodeConfigAsNotify } from "@/domain/workflow";
|
||||
import { useAntdForm, useZustandShallowSelector } from "@/hooks";
|
||||
import { useNotifyChannelsStore } from "@/stores/notify";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
@ -18,7 +18,7 @@ export type NotifyNodeFormProps = {
|
||||
node: WorkflowNode;
|
||||
};
|
||||
|
||||
const initFormModel = (): Partial<WorkflowNotifyNodeConfig> => {
|
||||
const initFormModel = (): Partial<WorkflowNodeConfigAsNotify> => {
|
||||
return {
|
||||
subject: "Completed!",
|
||||
message: "Your workflow has been completed on Certimate.",
|
||||
@ -57,7 +57,7 @@ const NotifyNodeForm = ({ node }: NotifyNodeFormProps) => {
|
||||
formPending,
|
||||
formProps,
|
||||
} = useAntdForm<z.infer<typeof formSchema>>({
|
||||
initialValues: (node?.config as WorkflowNotifyNodeConfig) ?? initFormModel(),
|
||||
initialValues: (node?.config as WorkflowNodeConfigAsNotify) ?? initFormModel(),
|
||||
onSubmit: async (values) => {
|
||||
await formInst.validateFields();
|
||||
await updateNode(
|
||||
|
@ -7,7 +7,7 @@ import { produce } from "immer";
|
||||
import { z } from "zod";
|
||||
|
||||
import Show from "@/components/Show";
|
||||
import { WORKFLOW_TRIGGERS, type WorkflowNode, type WorkflowStartNodeConfig } from "@/domain/workflow";
|
||||
import { WORKFLOW_TRIGGERS, type WorkflowNode, type WorkflowNodeConfigAsStart } from "@/domain/workflow";
|
||||
import { useAntdForm, useZustandShallowSelector } from "@/hooks";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { getNextCronExecutions, validCronExpression } from "@/utils/cron";
|
||||
@ -17,7 +17,7 @@ export type StartNodeFormProps = {
|
||||
node: WorkflowNode;
|
||||
};
|
||||
|
||||
const initFormModel = (): WorkflowStartNodeConfig => {
|
||||
const initFormModel = (): WorkflowNodeConfigAsStart => {
|
||||
return {
|
||||
trigger: WORKFLOW_TRIGGERS.AUTO,
|
||||
triggerCron: "0 0 * * *",
|
||||
@ -54,7 +54,7 @@ const StartNodeForm = ({ node }: StartNodeFormProps) => {
|
||||
formPending,
|
||||
formProps,
|
||||
} = useAntdForm<z.infer<typeof formSchema>>({
|
||||
initialValues: (node?.config as WorkflowStartNodeConfig) ?? initFormModel(),
|
||||
initialValues: (node?.config as WorkflowNodeConfigAsStart) ?? initFormModel(),
|
||||
onSubmit: async (values) => {
|
||||
await formInst.validateFields();
|
||||
await updateNode(
|
||||
|
@ -92,14 +92,14 @@ export type WorkflowNode = {
|
||||
validated?: boolean;
|
||||
};
|
||||
|
||||
export type WorkflowStartNodeConfig = {
|
||||
export type WorkflowNodeConfigAsStart = {
|
||||
trigger: string;
|
||||
triggerCron?: string;
|
||||
};
|
||||
|
||||
export type WorkflowApplyNodeConfig = {
|
||||
domain: string;
|
||||
email: string;
|
||||
export type WorkflowNodeConfigAsApply = {
|
||||
domains: string;
|
||||
contactEmail: string;
|
||||
provider: string;
|
||||
providerAccessId: string;
|
||||
keyAlgorithm: string;
|
||||
@ -108,22 +108,22 @@ export type WorkflowApplyNodeConfig = {
|
||||
disableFollowCNAME?: boolean;
|
||||
};
|
||||
|
||||
export type WorkflowDeployNodeConfig = {
|
||||
export type WorkflowNodeConfigAsDeploy = {
|
||||
provider: string;
|
||||
providerAccessId: string;
|
||||
certificate: string;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
|
||||
export type WorkflowNotifyNodeConfig = {
|
||||
export type WorkflowNodeConfigAsNotify = {
|
||||
channel: string;
|
||||
subject: string;
|
||||
message: string;
|
||||
};
|
||||
|
||||
export type WorkflowBranchNodeConfig = never;
|
||||
export type WorkflowNodeConfigAsBranch = never;
|
||||
|
||||
export type WorkflowEndNodeConfig = never;
|
||||
export type WorkflowNodeConfigAsEnd = never;
|
||||
|
||||
export type WorkflowNodeIO = {
|
||||
name: string;
|
||||
|
Loading…
x
Reference in New Issue
Block a user