perf: 证书仓库

v2-dev
xiaojunnuo 2025-01-15 01:05:34 +08:00
parent 52a4fd3318
commit 91e7f45a1c
48 changed files with 615 additions and 130 deletions

View File

@ -11,6 +11,7 @@ import { ICnameProxyService, IEmailService, IPluginConfigService, IUrlService }
import { FileStore } from "./file-store.js"; import { FileStore } from "./file-store.js";
import { cloneDeep, forEach, merge } from "lodash-es"; import { cloneDeep, forEach, merge } from "lodash-es";
import { INotificationService } from "../notification/index.js"; import { INotificationService } from "../notification/index.js";
import { taskEmitterCreate } from "../service/emit.js";
export type SysInfo = { export type SysInfo = {
//系统标题 //系统标题
@ -342,6 +343,10 @@ export class Executor {
signal: this.abort.signal, signal: this.abort.signal,
utils, utils,
user: this.options.user, user: this.options.user,
emitter: taskEmitterCreate({
step,
pipeline: this.pipeline,
}),
}; };
instance.setCtx(taskCtx); instance.setCtx(taskCtx);

View File

@ -7,9 +7,10 @@ import { CancelError, IContext, RunHistory, RunnableCollection } from "../core/i
import { HttpRequestConfig, ILogger, logger, utils } from "@certd/basic"; import { HttpRequestConfig, ILogger, logger, utils } from "@certd/basic";
import { HttpClient } from "@certd/basic"; import { HttpClient } from "@certd/basic";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { IPluginConfigService } from "../service/config"; import { IPluginConfigService } from "../service/config.js";
import { upperFirst } from "lodash-es"; import { upperFirst } from "lodash-es";
import { INotificationService } from "../notification"; import { INotificationService } from "../notification/index.js";
import { TaskEmitter } from "../service/emit.js";
export type PluginRequestHandleReq<T = any> = { export type PluginRequestHandleReq<T = any> = {
typeName: string; typeName: string;
@ -111,6 +112,8 @@ export type TaskInstanceContext = {
utils: typeof utils; utils: typeof utils;
//用户信息 //用户信息
user: UserInfo; user: UserInfo;
emitter: TaskEmitter;
}; };
export abstract class AbstractTaskPlugin implements ITaskPlugin { export abstract class AbstractTaskPlugin implements ITaskPlugin {

View File

@ -0,0 +1,68 @@
import { logger } from "@certd/basic";
import { Pipeline, Runnable } from "../dt";
export type PipelineEventListener = (...args: any[]) => Promise<void>;
export type PipelineEvent<T> = {
pipeline: Pipeline;
step: Runnable;
event: T;
};
export class PipelineEmitter {
events: Record<string, PipelineEventListener[]>;
constructor() {
this.events = {};
}
on(event: string, listener: PipelineEventListener) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(listener);
}
async emit<T>(name: string, event: PipelineEvent<T>) {
const listeners = this.events[name];
if (listeners) {
for (const listener of listeners) {
try {
await listener(event);
} catch (e) {
logger.error(`事件<${name}>监听器执行失败:`, e);
}
}
}
}
off(event: string, listener: PipelineEventListener) {
if (this.events[event]) {
this.events[event] = this.events[event].filter((l) => l !== listener);
}
}
once(event: string, listener: PipelineEventListener) {
const onceListener = async (...args: any[]) => {
this.off(event, onceListener);
await listener(...args);
};
this.on(event, onceListener);
}
}
export const pipelineEmitter = new PipelineEmitter();
export type TaskEmitterCreateReq = {
step: Runnable;
pipeline: Pipeline;
};
export type TaskEmitter = {
emit: <T>(name: string, event: T) => Promise<void>;
};
export function taskEmitterCreate(req: TaskEmitterCreateReq) {
return {
emit: async <T>(name: string, event: T) => {
await pipelineEmitter.emit(name, {
pipeline: req.pipeline,
step: req.step,
event,
});
},
} as TaskEmitter;
}

View File

@ -2,3 +2,4 @@ export * from "./email.js";
export * from "./cname.js"; export * from "./cname.js";
export * from "./config.js"; export * from "./config.js";
export * from "./url.js"; export * from "./url.js";
export * from "./emit.js";

View File

@ -1,4 +1,4 @@
import { AbstractTaskPlugin, IContext, NotificationBody, Step, TaskInput, TaskOutput } from "@certd/pipeline"; import { AbstractTaskPlugin, IContext, NotificationBody, Step, TaskEmitter, TaskInput, TaskOutput } from "@certd/pipeline";
import dayjs from "dayjs"; import dayjs from "dayjs";
import type { CertInfo } from "./acme.js"; import type { CertInfo } from "./acme.js";
import { CertReader } from "./cert-reader.js"; import { CertReader } from "./cert-reader.js";
@ -6,8 +6,11 @@ import JSZip from "jszip";
import { CertConverter } from "./convert.js"; import { CertConverter } from "./convert.js";
import { pick } from "lodash-es"; import { pick } from "lodash-es";
export { CertReader }; export const EVENT_CERT_APPLY_SUCCESS = "CertApply.success";
export type { CertInfo };
export async function emitCertApplySuccess(emitter: TaskEmitter, cert: CertReader) {
await emitter.emit(EVENT_CERT_APPLY_SUCCESS, cert);
}
export abstract class CertApplyBasePlugin extends AbstractTaskPlugin { export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
@TaskInput({ @TaskInput({
@ -119,7 +122,7 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
abstract onInit(): Promise<void>; abstract onInit(): Promise<void>;
abstract doCertApply(): Promise<any>; abstract doCertApply(): Promise<CertReader>;
async execute(): Promise<string | void> { async execute(): Promise<string | void> {
const oldCert = await this.condition(); const oldCert = await this.condition();
@ -130,6 +133,8 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
const cert = await this.doCertApply(); const cert = await this.doCertApply();
if (cert != null) { if (cert != null) {
await this.output(cert, true); await this.output(cert, true);
await emitCertApplySuccess(this.ctx.emitter, cert);
//清空后续任务的状态,让后续任务能够重新执行 //清空后续任务的状态,让后续任务能够重新执行
this.clearLastStatus(); this.clearLastStatus();
@ -234,28 +239,10 @@ cert.jksjks格式证书文件java服务器使用
// return null; // return null;
// } // }
let inputChanged = false;
//判断域名有没有变更
/**
* "renewDays": 35,
* "certApplyPlugin": "CertApply",
* "sslProvider": "letsencrypt",
* "privateKeyType": "rsa_2048_pkcs1",
* "dnsProviderType": "aliyun",
* "domains": [
* "*.handsfree.work"
* ],
* "email": "xiaojunnuo@qq.com",
* "dnsProviderAccess": 3,
* "useProxy": false,
* "skipLocalVerify": false,
* "successNotify": true,
* "pfxPassword": "123456"
*/
const checkInputChanges = ["domains", "sslProvider", "privateKeyType", "dnsProviderType", "pfxPassword"]; const checkInputChanges = ["domains", "sslProvider", "privateKeyType", "dnsProviderType", "pfxPassword"];
const oldInput = JSON.stringify(pick(this.lastStatus?.input, checkInputChanges)); const oldInput = JSON.stringify(pick(this.lastStatus?.input, checkInputChanges));
const thisInput = JSON.stringify(pick(this, checkInputChanges)); const thisInput = JSON.stringify(pick(this, checkInputChanges));
inputChanged = oldInput !== thisInput; const inputChanged = oldInput !== thisInput;
this.logger.info(`旧参数:${oldInput}`); this.logger.info(`旧参数:${oldInput}`);
this.logger.info(`新参数:${thisInput}`); this.logger.info(`新参数:${thisInput}`);

View File

@ -2,7 +2,7 @@ import { CertInfo } from "./acme.js";
import fs from "fs"; import fs from "fs";
import os from "os"; import os from "os";
import path from "path"; import path from "path";
import { crypto } from "@certd/acme-client"; import { CertificateInfo, crypto } from "@certd/acme-client";
import { ILogger } from "@certd/basic"; import { ILogger } from "@certd/basic";
import dayjs from "dayjs"; import dayjs from "dayjs";
@ -21,37 +21,22 @@ export type CertReaderHandle = (ctx: CertReaderHandleContext) => Promise<void>;
export type HandleOpts = { logger: ILogger; handle: CertReaderHandle }; export type HandleOpts = { logger: ILogger; handle: CertReaderHandle };
export class CertReader { export class CertReader {
cert: CertInfo; cert: CertInfo;
oc: string; //仅证书非fullchain证书
crt: string;
key: string;
csr: string;
ic: string; //中间证书
one: string; //crt + key 合成一个pem文件
detail: any; detail: CertificateInfo;
expires: number; expires: number;
constructor(certInfo: CertInfo) { constructor(certInfo: CertInfo) {
this.cert = certInfo; this.cert = certInfo;
this.crt = certInfo.crt;
this.key = certInfo.key;
this.csr = certInfo.csr;
this.ic = certInfo.ic; if (!certInfo.ic) {
if (!this.ic) { this.cert.ic = this.getIc();
this.ic = this.getIc();
this.cert.ic = this.ic;
} }
this.oc = certInfo.oc; if (!certInfo.oc) {
if (!this.oc) { this.cert.oc = this.getOc();
this.oc = this.getOc();
this.cert.oc = this.oc;
} }
this.one = certInfo.one; if (!certInfo.one) {
if (!this.one) { this.cert.one = this.cert.crt + "\n" + this.cert.key;
this.one = this.crt + "\n" + this.key;
this.cert.one = this.one;
} }
const { detail, expires } = this.getCrtDetail(this.cert.crt); const { detail, expires } = this.getCrtDetail(this.cert.crt);
@ -62,13 +47,13 @@ export class CertReader {
getIc() { getIc() {
//中间证书ic 就是crt的第一个 -----END CERTIFICATE----- 之后的内容 //中间证书ic 就是crt的第一个 -----END CERTIFICATE----- 之后的内容
const endStr = "-----END CERTIFICATE-----"; const endStr = "-----END CERTIFICATE-----";
const firstBlockEndIndex = this.crt.indexOf(endStr); const firstBlockEndIndex = this.cert.crt.indexOf(endStr);
const start = firstBlockEndIndex + endStr.length + 1; const start = firstBlockEndIndex + endStr.length + 1;
if (this.crt.length <= start) { if (this.cert.crt.length <= start) {
return ""; return "";
} }
const ic = this.crt.substring(start); const ic = this.cert.crt.substring(start);
if (ic == null) { if (ic == null) {
return ""; return "";
} }
@ -78,7 +63,7 @@ export class CertReader {
getOc() { getOc() {
//原始证书 就是crt的第一个 -----END CERTIFICATE----- 之前的内容 //原始证书 就是crt的第一个 -----END CERTIFICATE----- 之前的内容
const endStr = "-----END CERTIFICATE-----"; const endStr = "-----END CERTIFICATE-----";
const arr = this.crt.split(endStr); const arr = this.cert.crt.split(endStr);
return arr[0] + endStr; return arr[0] + endStr;
} }

View File

@ -10,7 +10,7 @@ import { CertApplyBasePlugin } from "./base.js";
import { GoogleClient } from "../../libs/google.js"; import { GoogleClient } from "../../libs/google.js";
import { EabAccess } from "../../access"; import { EabAccess } from "../../access";
import { httpChallengeUploaderFactory } from "./uploads/factory.js"; import { httpChallengeUploaderFactory } from "./uploads/factory.js";
export * from "./base.js";
export type { CertInfo }; export type { CertInfo };
export * from "./cert-reader.js"; export * from "./cert-reader.js";
export type CnameRecordInput = { export type CnameRecordInput = {

View File

@ -92,7 +92,7 @@ export const certdResources = [
}, },
icon: "ion:shield-checkmark-outline", icon: "ion:shield-checkmark-outline",
auth: true, auth: true,
isMenu: false isMenu: true
} }
}, },
{ {

View File

@ -2,6 +2,7 @@
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud"; import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
import { pipelineGroupApi } from "./api"; import { pipelineGroupApi } from "./api";
import dayjs from "dayjs";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet { export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const { t } = useI18n(); const { t } = useI18n();
@ -78,23 +79,23 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
show: false show: false
} }
}, },
domain: { // domain: {
title: "主域名", // title: "主域名",
search: { // search: {
show: true // show: true
}, // },
type: "text", // type: "text",
form: { // form: {
show: false // show: false
}, // },
column: { // column: {
width: 180, // width: 180,
sorter: true, // sorter: true,
component: { // component: {
name: "fs-values-format" // name: "fs-values-format"
} // }
} // }
}, // },
domains: { domains: {
title: "全部域名", title: "全部域名",
search: { search: {
@ -105,10 +106,11 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
rules: [{ required: true, message: "请输入域名" }] rules: [{ required: true, message: "请输入域名" }]
}, },
column: { column: {
width: 350, width: 450,
sorter: true, sorter: true,
component: { component: {
name: "fs-values-format" name: "fs-values-format",
color: "auto"
} }
} }
}, },
@ -132,7 +134,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
show: false show: false
}, },
column: { column: {
width: 250, width: 280,
sorter: true, sorter: true,
component: {} component: {}
} }
@ -160,7 +162,17 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
show: false show: false
}, },
column: { column: {
sorter: true sorter: true,
cellRender({ value }) {
if (!value) {
return "-";
}
const expireDate = dayjs(value).format("YYYY-MM-DD");
const leftDays = dayjs(value).diff(dayjs(), "day");
const color = leftDays < 20 ? "red" : "#389e0d";
const percent = (leftDays / 90) * 100;
return <a-progress title={expireDate + "过期"} percent={percent} strokeColor={color} format={(percent: number) => `${leftDays}`} />;
}
} }
}, },
fromType: { fromType: {

View File

@ -3,7 +3,7 @@
<template #header> <template #header>
<div class="title"> <div class="title">
证书仓库 证书仓库
<span class="sub">管理证书后续将支持手动上传证书并部署</span> <span class="sub">从流水线生成的证书后续将支持手动上传证书并部署</span>
</div> </div>
</template> </template>
<fs-crud ref="crudRef" v-bind="crudBinding"> </fs-crud> <fs-crud ref="crudRef" v-bind="crudBinding"> </fs-crud>

View File

@ -0,0 +1,54 @@
import { request } from "/src/api/service";
export function createApi() {
const apiPrefix = "/open/cert";
return {
async GetList(query: any) {
return await request({
url: apiPrefix + "/page",
method: "post",
data: query
});
},
async AddObj(obj: any) {
return await request({
url: apiPrefix + "/add",
method: "post",
data: obj
});
},
async UpdateObj(obj: any) {
return await request({
url: apiPrefix + "/update",
method: "post",
data: obj
});
},
async DelObj(id: number) {
return await request({
url: apiPrefix + "/delete",
method: "post",
params: { id }
});
},
async GetObj(id: number) {
return await request({
url: apiPrefix + "/info",
method: "post",
params: { id }
});
},
async ListAll() {
return await request({
url: apiPrefix + "/all",
method: "post"
});
}
};
}
export const pipelineGroupApi = createApi();

View File

@ -0,0 +1,206 @@
// @ts-ignore
import { useI18n } from "vue-i18n";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
import { pipelineGroupApi } from "./api";
import dayjs from "dayjs";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const { t } = useI18n();
const api = pipelineGroupApi;
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetList(query);
};
const editRequest = async (req: EditReq) => {
const { form, row } = req;
form.id = row.id;
const res = await api.UpdateObj(form);
return res;
};
const delRequest = async (req: DelReq) => {
const { row } = req;
return await api.DelObj(row.id);
};
const addRequest = async (req: AddReq) => {
const { form } = req;
const res = await api.AddObj(form);
return res;
};
return {
crudOptions: {
request: {
pageRequest,
addRequest,
editRequest,
delRequest
},
form: {
labelCol: {
//固定label宽度
span: null,
style: {
width: "100px"
}
},
col: {
span: 22
},
wrapper: {
width: 600
}
},
actionbar: { show: false },
rowHandle: {
width: 200,
fixed: "right",
buttons: {
view: { show: false },
copy: { show: false },
edit: { show: false },
remove: { show: false }
}
},
columns: {
id: {
title: "ID",
key: "id",
type: "number",
search: {
show: false
},
column: {
width: 100,
editable: {
disabled: true
}
},
form: {
show: false
}
},
// domain: {
// title: "主域名",
// search: {
// show: true
// },
// type: "text",
// form: {
// show: false
// },
// column: {
// width: 180,
// sorter: true,
// component: {
// name: "fs-values-format"
// }
// }
// },
domains: {
title: "全部域名",
search: {
show: false
},
type: "text",
form: {
rules: [{ required: true, message: "请输入域名" }]
},
column: {
width: 450,
sorter: true,
component: {
name: "fs-values-format",
color: "auto"
}
}
},
domainCount: {
title: "域名数量",
type: "number",
form: {
show: false
},
column: {
width: 120,
sorter: true,
show: false
}
},
"pipeline.title": {
title: "已关联流水线",
search: { show: false },
type: "link",
form: {
show: false
},
column: {
width: 280,
sorter: true,
component: {}
}
},
applyTime: {
title: "申请时间",
search: {
show: false
},
type: "datetime",
form: {
show: false
},
column: {
sorter: true
}
},
expiresTime: {
title: "过期时间",
search: {
show: true
},
type: "date",
form: {
show: false
},
column: {
sorter: true,
cellRender({ value }) {
if (!value) {
return "-";
}
const expireDate = dayjs(value).format("YYYY-MM-DD");
const leftDays = dayjs(value).diff(dayjs(), "day");
const color = leftDays < 20 ? "red" : "#389e0d";
const percent = (leftDays / 90) * 100;
return <a-progress title={expireDate + "过期"} percent={percent} strokeColor={color} format={(percent: number) => `${leftDays}`} />;
}
}
},
fromType: {
title: "来源",
search: {
show: true
},
type: "text",
form: { show: false },
column: {
width: 100,
sorter: true
}
},
certProvider: {
title: "证书颁发机构",
search: {
show: true
},
type: "text",
form: {
show: false
},
column: {
width: 400
}
}
}
}
};
}

View File

@ -0,0 +1,30 @@
<template>
<fs-page>
<template #header>
<div class="title">
证书仓库
<span class="sub">从流水线生成的证书后续将支持手动上传证书并部署</span>
</div>
</template>
<fs-crud ref="crudRef" v-bind="crudBinding"> </fs-crud>
</fs-page>
</template>
<script lang="ts" setup>
import { defineComponent, onActivated, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import { createApi } from "./api";
defineOptions({
name: "CertStore"
});
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: {} });
//
onMounted(() => {
crudExpose.doRefresh();
});
onActivated(() => {
crudExpose.doRefresh();
});
</script>

View File

@ -0,0 +1,15 @@
CREATE TABLE "cd_open_key"
(
"id" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
"user_id" integer,
"key_id" varchar(50),
"key_secret" varchar(100),
"disabled" boolean NOT NULL DEFAULT (false),
"create_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP),
"update_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP)
);
CREATE INDEX "index_open_key_user_id" ON "cd_open_key" ("user_id");
CREATE INDEX "index_open_key_key_id" ON "cd_open_key" ("key_id");

View File

@ -1,9 +1,9 @@
import { ALL, Body, Controller, Get, Inject, Post, Provide, Query } from '@midwayjs/core'; import { ALL, Body, Controller, Get, Inject, Post, Provide, Query } from '@midwayjs/core';
import { CodeException, Constants, EncryptService } from '@certd/lib-server'; import { CodeException, Constants, EncryptService } from '@certd/lib-server';
import { CertInfoService } from '../../modules/monitor/service/cert-info-service.js'; import { CertInfoService } from '../../../modules/monitor/service/cert-info-service.js';
import { CertInfo } from '@certd/plugin-cert'; import { CertInfo } from '@certd/plugin-cert';
import { OpenKey } from '../../modules/open/service/open-key-service.js'; import { OpenKey } from '../../../modules/open/service/open-key-service.js';
import { BaseOpenController } from './base-open-controller.js'; import { BaseOpenController } from '../base-open-controller.js';
export type CertGetReq = { export type CertGetReq = {
domains: string; domains: string;
@ -12,7 +12,7 @@ export type CertGetReq = {
/** /**
*/ */
@Provide() @Provide()
@Controller('/open/cert') @Controller('/api/v1/cert')
export class OpenCertController extends BaseOpenController { export class OpenCertController extends BaseOpenController {
@Inject() @Inject()
certInfoService: CertInfoService; certInfoService: CertInfoService;

View File

@ -1,6 +1,6 @@
import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core'; import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core';
import { AccessService, Constants } from '@certd/lib-server'; import { AccessService, Constants } from '@certd/lib-server';
import { AccessController } from '../../pipeline/access-controller.js'; import { AccessController } from '../../user/pipeline/access-controller.js';
import { checkComm } from '@certd/plus-core'; import { checkComm } from '@certd/plus-core';
/** /**

View File

@ -1,6 +1,6 @@
import { Body, Controller, Inject, Post, Provide } from '@midwayjs/core'; import { Body, Controller, Inject, Post, Provide } from '@midwayjs/core';
import { BaseController } from '@certd/lib-server'; import { BaseController } from '@certd/lib-server';
import { EmailService } from '../../modules/basic/service/email-service.js'; import { EmailService } from '../../../modules/basic/service/email-service.js';
import { Constants } from '@certd/lib-server'; import { Constants } from '@certd/lib-server';
/** /**

View File

@ -1,7 +1,7 @@
import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core'; import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core';
import { BaseController, Constants } from '@certd/lib-server'; import { BaseController, Constants } from '@certd/lib-server';
import { CnameRecordService } from '../../modules/cname/service/cname-record-service.js'; import { CnameRecordService } from '../../../modules/cname/service/cname-record-service.js';
import { CnameProviderService } from '../../modules/cname/service/cname-provider-service.js'; import { CnameProviderService } from '../../../modules/cname/service/cname-provider-service.js';
/** /**
* *

View File

@ -1,6 +1,6 @@
import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core'; import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core';
import { Constants, CrudController } from '@certd/lib-server'; import { Constants, CrudController } from '@certd/lib-server';
import { CnameRecordService } from '../../modules/cname/service/cname-record-service.js'; import { CnameRecordService } from '../../../modules/cname/service/cname-record-service.js';
/** /**
* *

View File

@ -1,9 +1,9 @@
import { Controller, Inject, Post, Provide } from '@midwayjs/core'; import { Controller, Inject, Post, Provide } from '@midwayjs/core';
import { BaseController, Constants } from '@certd/lib-server'; import { BaseController, Constants } from '@certd/lib-server';
import { UserService } from '../../modules/sys/authority/service/user-service.js'; import { UserService } from '../../../modules/sys/authority/service/user-service.js';
import { RoleService } from '../../modules/sys/authority/service/role-service.js'; import { RoleService } from '../../../modules/sys/authority/service/role-service.js';
import { PipelineService } from '../../modules/pipeline/service/pipeline-service.js'; import { PipelineService } from '../../../modules/pipeline/service/pipeline-service.js';
import { HistoryService } from '../../modules/pipeline/service/history-service.js'; import { HistoryService } from '../../../modules/pipeline/service/history-service.js';
export type ChartItem = { export type ChartItem = {
name: string; name: string;

View File

@ -1,7 +1,7 @@
import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core'; import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core';
import { LoginService } from '../../modules/login/service/login-service.js'; import { LoginService } from '../../../modules/login/service/login-service.js';
import { BaseController, Constants, SysPublicSettings, SysSettingsService } from '@certd/lib-server'; import { BaseController, Constants, SysPublicSettings, SysSettingsService } from '@certd/lib-server';
import { CodeService } from '../../modules/basic/service/code-service.js'; import { CodeService } from '../../../modules/basic/service/code-service.js';
import { checkComm } from '@certd/plus-core'; import { checkComm } from '@certd/plus-core';
/** /**

View File

@ -1,7 +1,7 @@
import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core'; import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core';
import { BaseController, Constants, SysSettingsService } from '@certd/lib-server'; import { BaseController, Constants, SysSettingsService } from '@certd/lib-server';
import { RegisterType, UserService } from '../../modules/sys/authority/service/user-service.js'; import { RegisterType, UserService } from '../../../modules/sys/authority/service/user-service.js';
import { CodeService } from '../../modules/basic/service/code-service.js'; import { CodeService } from '../../../modules/basic/service/code-service.js';
import { checkComm, checkPlus } from '@certd/plus-core'; import { checkComm, checkPlus } from '@certd/plus-core';
export type RegisterReq = { export type RegisterReq = {

View File

@ -1,7 +1,7 @@
import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core'; import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core';
import { BaseController, Constants } from '@certd/lib-server'; import { BaseController, Constants } from '@certd/lib-server';
import { UserService } from '../../modules/sys/authority/service/user-service.js'; import { UserService } from '../../../modules/sys/authority/service/user-service.js';
import { RoleService } from '../../modules/sys/authority/service/role-service.js'; import { RoleService } from '../../../modules/sys/authority/service/role-service.js';
/** /**
*/ */

View File

@ -1,8 +1,8 @@
import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core'; import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core';
import { CrudController } from '@certd/lib-server'; import { CrudController } from '@certd/lib-server';
import { Constants } from '@certd/lib-server'; import { Constants } from '@certd/lib-server';
import { UserSettingsService } from '../../modules/mine/service/user-settings-service.js'; import { UserSettingsService } from '../../../modules/mine/service/user-settings-service.js';
import { UserSettingsEntity } from '../../modules/mine/entity/user-settings.js'; import { UserSettingsEntity } from '../../../modules/mine/entity/user-settings.js';
/** /**
*/ */

View File

@ -1,8 +1,8 @@
import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core'; import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core';
import { Constants, CrudController } from '@certd/lib-server'; import { Constants, CrudController } from '@certd/lib-server';
import { AuthService } from '../../modules/sys/authority/service/auth-service.js'; import { AuthService } from '../../../modules/sys/authority/service/auth-service.js';
import { CertInfoService } from '../../modules/monitor/index.js'; import { CertInfoService } from '../../../modules/monitor/index.js';
import { PipelineService } from '../../modules/pipeline/service/pipeline-service.js'; import { PipelineService } from '../../../modules/pipeline/service/pipeline-service.js';
/** /**
*/ */

View File

@ -1,7 +1,7 @@
import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core'; import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core';
import { Constants, CrudController } from '@certd/lib-server'; import { Constants, CrudController } from '@certd/lib-server';
import { AuthService } from '../../modules/sys/authority/service/auth-service.js'; import { AuthService } from '../../../modules/sys/authority/service/auth-service.js';
import { SiteInfoService } from '../../modules/monitor/index.js'; import { SiteInfoService } from '../../../modules/monitor/service/site-info-service.js';
/** /**
*/ */

View File

@ -0,0 +1,64 @@
import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core';
import { Constants, CrudController } from '@certd/lib-server';
import { AuthService } from '../../../modules/sys/authority/service/auth-service.js';
import { OpenKeyService } from '../../../modules/open/service/open-key-service.js';
/**
*/
@Provide()
@Controller('/api/open/key')
export class OpenKeyController extends CrudController<OpenKeyService> {
@Inject()
service: OpenKeyService;
@Inject()
authService: AuthService;
getService(): OpenKeyService {
return this.service;
}
@Post('/page', { summary: Constants.per.authOnly })
async page(@Body(ALL) body: any) {
body.query = body.query ?? {};
body.query.userId = this.getUserId();
const res = await this.service.page({
query: body.query,
page: body.page,
sort: body.sort,
});
return this.ok(res);
}
@Post('/list', { summary: Constants.per.authOnly })
async list(@Body(ALL) body: any) {
body.query = body.query ?? {};
body.query.userId = this.getUserId();
return await super.list(body);
}
@Post('/add', { summary: Constants.per.authOnly })
async add(@Body(ALL) bean: any) {
bean.userId = this.getUserId();
const res = await this.service.add(bean);
return this.ok(res);
}
@Post('/update', { summary: Constants.per.authOnly })
async update(@Body(ALL) bean) {
await this.service.checkUserId(bean.id, this.getUserId());
delete bean.userId;
await this.service.update(bean);
return this.ok();
}
@Post('/info', { summary: Constants.per.authOnly })
async info(@Query('id') id: number) {
await this.service.checkUserId(id, this.getUserId());
return await super.info(id);
}
@Post('/delete', { summary: Constants.per.authOnly })
async delete(@Query('id') id: number) {
await this.service.checkUserId(id, this.getUserId());
return await super.delete(id);
}
}

View File

@ -1,7 +1,7 @@
import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core'; import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core';
import { Constants, CrudController } from '@certd/lib-server'; import { Constants, CrudController } from '@certd/lib-server';
import { AccessService } from '@certd/lib-server'; import { AccessService } from '@certd/lib-server';
import { AuthService } from '../../modules/sys/authority/service/auth-service.js'; import { AuthService } from '../../../modules/sys/authority/service/auth-service.js';
import { AccessDefine } from '@certd/pipeline'; import { AccessDefine } from '@certd/pipeline';
/** /**

View File

@ -1,7 +1,7 @@
import { Controller, Inject, Post, Provide, Query } from '@midwayjs/core'; import { Controller, Inject, Post, Provide, Query } from '@midwayjs/core';
import { PipelineService } from '../../modules/pipeline/service/pipeline-service.js'; import { PipelineService } from '../../../modules/pipeline/service/pipeline-service.js';
import { BaseController, Constants } from '@certd/lib-server'; import { BaseController, Constants } from '@certd/lib-server';
import { StorageService } from '../../modules/pipeline/service/storage-service.js'; import { StorageService } from '../../../modules/pipeline/service/storage-service.js';
@Provide() @Provide()
@Controller('/api/pi/cert') @Controller('/api/pi/cert')

View File

@ -1,5 +1,5 @@
import { ALL, Controller, Inject, Post, Provide, Query } from '@midwayjs/core'; import { ALL, Controller, Inject, Post, Provide, Query } from '@midwayjs/core';
import { DnsProviderService } from '../../modules/pipeline/service/dns-provider-service.js'; import { DnsProviderService } from '../../../modules/pipeline/service/dns-provider-service.js';
import { BaseController } from '@certd/lib-server'; import { BaseController } from '@certd/lib-server';
import { Constants } from '@certd/lib-server'; import { Constants } from '@certd/lib-server';

View File

@ -11,9 +11,9 @@ import {
TaskInstanceContext, TaskInstanceContext,
} from '@certd/pipeline'; } from '@certd/pipeline';
import { AccessService, AccessGetter } from '@certd/lib-server'; import { AccessService, AccessGetter } from '@certd/lib-server';
import { EmailService } from '../../modules/basic/service/email-service.js'; import { EmailService } from '../../../modules/basic/service/email-service.js';
import { http, HttpRequestConfig, logger, mergeUtils, utils } from '@certd/basic'; import { http, HttpRequestConfig, logger, mergeUtils, utils } from '@certd/basic';
import { NotificationService } from '../../modules/pipeline/service/notification-service.js'; import { NotificationService } from '../../../modules/pipeline/service/notification-service.js';
@Provide() @Provide()
@Controller('/api/pi/handle') @Controller('/api/pi/handle')

View File

@ -1,14 +1,14 @@
import { ALL, Body, Controller, Get, Inject, Post, Provide, Query } from '@midwayjs/core'; import { ALL, Body, Controller, Get, Inject, Post, Provide, Query } from '@midwayjs/core';
import { CommonException, Constants, CrudController, PermissionException } from '@certd/lib-server'; import { CommonException, Constants, CrudController, PermissionException } from '@certd/lib-server';
import { PipelineEntity } from '../../modules/pipeline/entity/pipeline.js'; import { PipelineEntity } from '../../../modules/pipeline/entity/pipeline.js';
import { HistoryService } from '../../modules/pipeline/service/history-service.js'; import { HistoryService } from '../../../modules/pipeline/service/history-service.js';
import { HistoryLogService } from '../../modules/pipeline/service/history-log-service.js'; import { HistoryLogService } from '../../../modules/pipeline/service/history-log-service.js';
import { HistoryEntity } from '../../modules/pipeline/entity/history.js'; import { HistoryEntity } from '../../../modules/pipeline/entity/history.js';
import { HistoryLogEntity } from '../../modules/pipeline/entity/history-log.js'; import { HistoryLogEntity } from '../../../modules/pipeline/entity/history-log.js';
import { PipelineService } from '../../modules/pipeline/service/pipeline-service.js'; import { PipelineService } from '../../../modules/pipeline/service/pipeline-service.js';
import * as fs from 'fs'; import * as fs from 'fs';
import { logger } from '@certd/basic'; import { logger } from '@certd/basic';
import { AuthService } from '../../modules/sys/authority/service/auth-service.js'; import { AuthService } from '../../../modules/sys/authority/service/auth-service.js';
import { SysSettingsService } from '@certd/lib-server'; import { SysSettingsService } from '@certd/lib-server';
import { In } from 'typeorm'; import { In } from 'typeorm';

View File

@ -1,7 +1,7 @@
import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core'; import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core';
import { Constants, CrudController, ValidateException } from '@certd/lib-server'; import { Constants, CrudController, ValidateException } from '@certd/lib-server';
import { NotificationService } from '../../modules/pipeline/service/notification-service.js'; import { NotificationService } from '../../../modules/pipeline/service/notification-service.js';
import { AuthService } from '../../modules/sys/authority/service/auth-service.js'; import { AuthService } from '../../../modules/sys/authority/service/auth-service.js';
import { NotificationDefine } from '@certd/pipeline'; import { NotificationDefine } from '@certd/pipeline';
import { checkPlus } from '@certd/plus-core'; import { checkPlus } from '@certd/plus-core';

View File

@ -0,0 +1,22 @@
import { Autoload, Init, Inject, Scope, ScopeEnum } from '@midwayjs/core';
import { CertInfoService } from '../monitor/index.js';
import { pipelineEmitter } from '@certd/pipeline';
import { CertReader, EVENT_CERT_APPLY_SUCCESS } from '@certd/plugin-cert';
import { PipelineEvent } from '@certd/pipeline/dist/service/emit.js';
@Autoload()
@Scope(ScopeEnum.Request, { allowDowngrade: true })
export class AutoEPipelineEmitterRegister {
@Inject()
certInfoService: CertInfoService;
@Init()
async init() {
await this.onCertApplySuccess();
}
async onCertApplySuccess() {
pipelineEmitter.on(EVENT_CERT_APPLY_SUCCESS, async (event: PipelineEvent<CertReader>) => {
await this.certInfoService.updateCert(event.pipeline.id, event.event);
});
}
}

View File

@ -1,4 +1,4 @@
import { Inject, Provide } from '@midwayjs/core'; import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
import { cache, isDev, randomNumber } from '@certd/basic'; import { cache, isDev, randomNumber } from '@certd/basic';
import { SysSettingsService, SysSiteInfo } from '@certd/lib-server'; import { SysSettingsService, SysSiteInfo } from '@certd/lib-server';
import { SmsServiceFactory } from '../sms/factory.js'; import { SmsServiceFactory } from '../sms/factory.js';
@ -13,6 +13,7 @@ import { isComm } from '@certd/plus-core';
/** /**
*/ */
@Provide() @Provide()
@Scope(ScopeEnum.Request, { allowDowngrade: true })
export class CodeService { export class CodeService {
@Inject() @Inject()
sysSettingsService: SysSettingsService; sysSettingsService: SysSettingsService;

View File

@ -1,4 +1,4 @@
import { Config, Inject, Provide } from '@midwayjs/core'; import { Config, Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
import { UserService } from '../../sys/authority/service/user-service.js'; import { UserService } from '../../sys/authority/service/user-service.js';
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import { CommonException } from '@certd/lib-server'; import { CommonException } from '@certd/lib-server';
@ -14,6 +14,7 @@ import { CodeService } from '../../basic/service/code-service.js';
* *
*/ */
@Provide() @Provide()
@Scope(ScopeEnum.Request, { allowDowngrade: true })
export class LoginService { export class LoginService {
@Inject() @Inject()
userService: UserService; userService: UserService;

View File

@ -22,7 +22,7 @@ export class CertInfoEntity {
pipelineId: number; pipelineId: number;
@Column({ name: 'apply_time', comment: '申请时间' }) @Column({ name: 'apply_time', comment: '申请时间' })
applyTime: string; applyTime: number;
@Column({ name: 'from_type', comment: '来源' }) @Column({ name: 'from_type', comment: '来源' })
fromType: string; fromType: string;

View File

@ -0,0 +1,5 @@
export * from './entity/site-info.js';
export * from './entity/cert-info.js';
export * from './service/cert-info-service.js';
export * from './service/site-info-service.js';

View File

@ -1,4 +1,4 @@
import { Provide } from '@midwayjs/core'; import { Provide, Scope, ScopeEnum } from '@midwayjs/core';
import { BaseService, CodeException, Constants, PageReq } from '@certd/lib-server'; import { BaseService, CodeException, Constants, PageReq } from '@certd/lib-server';
import { InjectEntityModel } from '@midwayjs/typeorm'; import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm'; import { Repository } from 'typeorm';
@ -7,6 +7,7 @@ import { utils } from '@certd/basic';
import { CertInfo, CertReader } from '@certd/plugin-cert'; import { CertInfo, CertReader } from '@certd/plugin-cert';
@Provide() @Provide()
@Scope(ScopeEnum.Request, { allowDowngrade: true })
export class CertInfoService extends BaseService<CertInfoEntity> { export class CertInfoService extends BaseService<CertInfoEntity> {
@InjectEntityModel(CertInfoEntity) @InjectEntityModel(CertInfoEntity)
repository: Repository<CertInfoEntity>; repository: Repository<CertInfoEntity>;
@ -91,4 +92,28 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
const certReader = new CertReader(certInfo); const certReader = new CertReader(certInfo);
return certReader.toCertInfo(); return certReader.toCertInfo();
} }
async updateCert(pipelineId: number, certReader: CertReader) {
const found = await this.repository.findOne({
where: {
pipelineId,
},
});
if (!found) {
return;
}
const bean = new CertInfoEntity();
bean.id = found.id;
const certInfo = certReader.toCertInfo();
bean.certInfo = JSON.stringify(certInfo);
bean.applyTime = new Date().getTime();
const domains = certReader.detail.domains.altNames;
bean.domains = domains.join(',');
bean.domain = domains[0];
bean.domainCount = domains.length;
bean.expiresTime = certReader.expires;
bean.certProvider = certReader.detail.issuer.commonName;
await this.addOrUpdate(bean);
}
} }

View File

@ -1,4 +1,4 @@
import { Inject, Provide } from '@midwayjs/core'; import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
import { BaseService, NeedSuiteException, NeedVIPException, SysSettingsService } from '@certd/lib-server'; import { BaseService, NeedSuiteException, NeedVIPException, SysSettingsService } from '@certd/lib-server';
import { InjectEntityModel } from '@midwayjs/typeorm'; import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm'; import { Repository } from 'typeorm';
@ -12,6 +12,7 @@ import { isComm, isPlus } from '@certd/plus-core';
import { UserSuiteService } from '@certd/commercial-core'; import { UserSuiteService } from '@certd/commercial-core';
@Provide() @Provide()
@Scope(ScopeEnum.Request, { allowDowngrade: true })
export class SiteInfoService extends BaseService<SiteInfoEntity> { export class SiteInfoService extends BaseService<SiteInfoEntity> {
@InjectEntityModel(SiteInfoEntity) @InjectEntityModel(SiteInfoEntity)
repository: Repository<SiteInfoEntity>; repository: Repository<SiteInfoEntity>;

View File

@ -5,13 +5,13 @@ export class OpenKeyEntity {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id: number; id: number;
@Column({ name: 'user_id', comment: '用户id', unique: true }) @Column({ name: 'user_id', comment: '用户id' })
userId: number; userId: number;
@Column({ name: 'key_id', comment: 'keyId', unique: true }) @Column({ name: 'key_id', comment: 'keyId' })
keyId: string; keyId: string;
@Column({ name: 'key_secret', comment: 'keySecret', unique: true }) @Column({ name: 'key_secret', comment: 'keySecret' })
keySecret: string; keySecret: string;
@Column({ name: 'create_time', comment: '创建时间', default: () => 'CURRENT_TIMESTAMP' }) @Column({ name: 'create_time', comment: '创建时间', default: () => 'CURRENT_TIMESTAMP' })

View File

@ -1,4 +1,4 @@
import { Provide } from '@midwayjs/core'; import { Provide, Scope, ScopeEnum } from '@midwayjs/core';
import { BaseService, Constants, CodeException, PageReq } from '@certd/lib-server'; import { BaseService, Constants, CodeException, PageReq } from '@certd/lib-server';
import { InjectEntityModel } from '@midwayjs/typeorm'; import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm'; import { Repository } from 'typeorm';
@ -13,6 +13,7 @@ export type OpenKey = {
encrypt: boolean; encrypt: boolean;
}; };
@Provide() @Provide()
@Scope(ScopeEnum.Request, { allowDowngrade: true })
export class OpenKeyService extends BaseService<OpenKeyEntity> { export class OpenKeyService extends BaseService<OpenKeyEntity> {
@InjectEntityModel(OpenKeyEntity) @InjectEntityModel(OpenKeyEntity)
repository: Repository<OpenKeyEntity>; repository: Repository<OpenKeyEntity>;

View File

@ -1,5 +1,5 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
import { CertInfo, CertReader } from '@certd/plugin-cert'; import { CertInfo } from '@certd/plugin-cert';
import { DogeClient } from '../../lib/index.js'; import { DogeClient } from '../../lib/index.js';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
@ -68,11 +68,10 @@ export class DogeCloudDeployToCDNPlugin extends AbstractTaskPlugin {
} }
async updateCert() { async updateCert() {
const certReader = new CertReader(this.cert);
const data = await this.dogeClient.request('/cdn/cert/upload.json', { const data = await this.dogeClient.request('/cdn/cert/upload.json', {
note: 'certd-' + dayjs().format('YYYYMMDDHHmmss'), note: 'certd-' + dayjs().format('YYYYMMDDHHmmss'),
cert: certReader.crt, cert: this.cert.crt,
private: certReader.key, private: this.cert.key,
}); });
return data.id; return data.id;
} }