From 303097b835bdb72bc717269a793abbc471e8f84b Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Thu, 18 Jul 2024 11:17:13 +0800 Subject: [PATCH] chore: 1 --- packages/core/pipeline/package.json | 1 - packages/core/pipeline/src/core/executor.ts | 16 +++-- packages/libs/k8s/.gitignore | 4 +- packages/libs/k8s/src/lib/k8s.client.ts | 1 - packages/libs/k8s/tsconfig.json | 2 +- .../src/plugin/cert-plugin/index.ts | 63 +++++++++++++++---- .../db/migration-pg/v10005__password2.sql | 1 + packages/ui/certd-server/src/config/loader.ts | 8 ++- packages/ui/certd-server/src/configuration.ts | 7 ++- .../modules/authority/service/user-service.ts | 49 ++++++++------- .../pipeline/service/pipeline-service.ts | 30 ++++----- .../controller/sys-settings-controller.ts | 16 ++--- .../plugin/deploy-to-ack-ingress/index.ts | 38 ++--------- .../plugin-demo/plugins/plugin-test.ts | 3 + 14 files changed, 133 insertions(+), 106 deletions(-) diff --git a/packages/core/pipeline/package.json b/packages/core/pipeline/package.json index 1e0ffd6d..3350f6ec 100644 --- a/packages/core/pipeline/package.json +++ b/packages/core/pipeline/package.json @@ -21,7 +21,6 @@ "qs": "^6.11.2" }, "devDependencies": { - "@certd/acme-client": "workspace:^1.21.2", "@rollup/plugin-commonjs": "^23.0.4", "@rollup/plugin-json": "^6.0.0", "@rollup/plugin-node-resolve": "^15.0.1", diff --git a/packages/core/pipeline/src/core/executor.ts b/packages/core/pipeline/src/core/executor.ts index be7e14b3..f1fc620b 100644 --- a/packages/core/pipeline/src/core/executor.ts +++ b/packages/core/pipeline/src/core/executor.ts @@ -282,12 +282,16 @@ export class Executor { continue; } if (notification.type === "email") { - this.options.emailService?.send({ - userId: this.pipeline.userId, - subject, - content, - receivers: notification.options.receivers, - }); + try { + this.options.emailService?.send({ + userId: this.pipeline.userId, + subject, + content, + receivers: notification.options.receivers, + }); + } catch (e) { + logger.error("send email error", e); + } } } } diff --git a/packages/libs/k8s/.gitignore b/packages/libs/k8s/.gitignore index 5ee37c64..53ea5e39 100644 --- a/packages/libs/k8s/.gitignore +++ b/packages/libs/k8s/.gitignore @@ -23,4 +23,6 @@ dist-ssr *.sln *.sw? -test/user.secret.ts \ No newline at end of file +src/test/user.secret.ts + +src/**/*.js \ No newline at end of file diff --git a/packages/libs/k8s/src/lib/k8s.client.ts b/packages/libs/k8s/src/lib/k8s.client.ts index ef4d62c4..84fd6280 100644 --- a/packages/libs/k8s/src/lib/k8s.client.ts +++ b/packages/libs/k8s/src/lib/k8s.client.ts @@ -2,7 +2,6 @@ import kubernetesClient from 'kubernetes-client'; import dns from 'dns'; import { logger } from '@certd/pipeline'; -// @ts-ignore const { KubeConfig, Client, Request } = kubernetesClient; export class K8sClient { diff --git a/packages/libs/k8s/tsconfig.json b/packages/libs/k8s/tsconfig.json index 4a95cdd5..d97da42d 100644 --- a/packages/libs/k8s/tsconfig.json +++ b/packages/libs/k8s/tsconfig.json @@ -36,6 +36,6 @@ "*.ts", "dist", "node_modules", - "test" + "src/test" ], } diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts index 854d1ce6..5dd3a383 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts @@ -44,7 +44,7 @@ export class CertApplyPlugin extends AbstractTaskPlugin { "3、多级子域名要分成多个域名输入(*.foo.com的证书不能用于xxx.yyy.foo.com、foo.com)\n" + "4、输入一个回车之后,再输入下一个", }) - domains!: string; + domains!: string[]; @TaskInput({ title: "邮箱", @@ -143,9 +143,20 @@ export class CertApplyPlugin extends AbstractTaskPlugin { forceUpdate!: string; @TaskInput({ - title: "CsrInfo", - helper: "暂时没有用", + title: "成功后邮件通知", + value: true, + component: { + name: "a-switch", + vModel: "checked", + }, + helper: "申请成功后是否发送邮件通知", }) + successNotify = true; + + // @TaskInput({ + // title: "CsrInfo", + // helper: "暂时没有用", + // }) csrInfo!: string; @TaskInput({ @@ -196,6 +207,10 @@ export class CertApplyPlugin extends AbstractTaskPlugin { await this.output(cert, true); //清空后续任务的状态,让后续任务能够重新执行 this.clearLastStatus(); + + if (this.successNotify) { + await this.sendSuccessEmail(); + } } else { throw new Error("申请证书失败"); } @@ -296,16 +311,25 @@ export class CertApplyPlugin extends AbstractTaskPlugin { dnsProvider.setCtx(context); await dnsProvider.onInstance(); - const cert = await this.acme.order({ - email, - domains, - dnsProvider, - csrInfo, - isTest: false, - }); + try { + const cert = await this.acme.order({ + email, + domains, + dnsProvider, + csrInfo, + isTest: false, + }); - const certInfo = this.formatCerts(cert); - return new CertReader(certInfo); + const certInfo = this.formatCerts(cert); + return new CertReader(certInfo); + } catch (e: any) { + const message: string = e.message; + if (message.indexOf("redundant with a wildcard domain in the same request") >= 0) { + this.logger.error(e); + throw new Error(`通配符域名已经包含了普通域名,请删除其中一个(${message})`); + } + throw e; + } } formatCert(pem: string) { @@ -349,6 +373,21 @@ export class CertApplyPlugin extends AbstractTaskPlugin { leftDays, }; } + + private async sendSuccessEmail() { + try { + this.logger.info("发送成功邮件通知:" + this.email); + const subject = `【CertD】证书申请成功【${this.domains[0]}】`; + await this.ctx.emailService.send({ + userId: this.ctx.pipeline.userId, + receivers: [this.email], + subject: subject, + content: `证书申请成功,域名:${this.domains.join(",")}`, + }); + } catch (e) { + this.logger.error("send email error", e); + } + } } new CertApplyPlugin(); diff --git a/packages/ui/certd-server/db/migration-pg/v10005__password2.sql b/packages/ui/certd-server/db/migration-pg/v10005__password2.sql index 6d279f03..e1525be2 100644 --- a/packages/ui/certd-server/db/migration-pg/v10005__password2.sql +++ b/packages/ui/certd-server/db/migration-pg/v10005__password2.sql @@ -2,3 +2,4 @@ INSERT INTO sys_settings (key, title, setting,access) VALUES ('sys.install','安 ALTER TABLE sys_user ADD COLUMN password_version integer DEFAULT 1; ALTER TABLE sys_user ADD COLUMN password_salt varchar(36); +ALTER TABLE sys_user ALTER COLUMN password varchar(100); diff --git a/packages/ui/certd-server/src/config/loader.ts b/packages/ui/certd-server/src/config/loader.ts index 02b91e7a..bc380611 100644 --- a/packages/ui/certd-server/src/config/loader.ts +++ b/packages/ui/certd-server/src/config/loader.ts @@ -31,9 +31,11 @@ export function load(config, env = '') { // Get document, or throw exception on error logger.info('load config', env); const yamlPath = path.join(process.cwd(), `.env.${env}.yaml`); - const doc = yaml.load(fs.readFileSync(yamlPath, 'utf8')); - _.merge(doc, parseEnv(config)); - return doc; + if (fs.existsSync(yamlPath)) { + const doc = yaml.load(fs.readFileSync(yamlPath, 'utf8')); + return _.merge(doc, parseEnv(config)); + } + return parseEnv(config); } export function mergeConfig(config: any, envType: string) { diff --git a/packages/ui/certd-server/src/configuration.ts b/packages/ui/certd-server/src/configuration.ts index 4b7495a4..2e85a1d1 100644 --- a/packages/ui/certd-server/src/configuration.ts +++ b/packages/ui/certd-server/src/configuration.ts @@ -21,6 +21,11 @@ import ProductionConfig from './config/config.production.js'; import PreviewConfig from './config/config.preview.js'; import UnittestConfig from './config/config.unittest.js'; +process.on('uncaughtException', error => { + console.error('未捕获的异常:', error); + // 在这里可以添加日志记录、发送错误通知等操作 +}); + @Configuration({ imports: [ koa, @@ -50,7 +55,7 @@ export class MainConfiguration { async onReady() { // add middleware - this.app.useMiddleware([ReportMiddleware]); + // this.app.useMiddleware([ReportMiddleware]); // add filter // this.app.useFilter([NotFoundFilter, DefaultErrorFilter]); //跨域 diff --git a/packages/ui/certd-server/src/modules/authority/service/user-service.ts b/packages/ui/certd-server/src/modules/authority/service/user-service.ts index fa35c693..cc22c61a 100644 --- a/packages/ui/certd-server/src/modules/authority/service/user-service.ts +++ b/packages/ui/certd-server/src/modules/authority/service/user-service.ts @@ -13,6 +13,8 @@ import { Constants } from '../../../basic/constants.js'; import { UserRoleEntity } from '../entity/user-role.js'; import { randomText } from 'svg-captcha'; import bcrypt from 'bcryptjs'; +import { SysSettingsService } from '../../system/service/sys-settings-service.js'; +import { SysInstallInfo } from '../../system/service/models.js'; /** * 系统用户 @@ -29,6 +31,9 @@ export class UserService extends BaseService { @Inject() userRoleService: UserRoleService; + @Inject() + sysSettingsService: SysSettingsService; + getRepository() { return this.repository; } @@ -88,7 +93,7 @@ export class UserService extends BaseService { delete param.username; if (!_.isEmpty(param.password)) { param.passwordVersion = 2; - param.password = this.genPassword(param.password, param.passwordVersion); + param.password = await this.genPassword(param.password, param.passwordVersion); } else { delete param.password; } @@ -96,30 +101,33 @@ export class UserService extends BaseService { await this.roleService.updateRoles(param.id, param.roles); } - private genPassword(plainPassword: any, passwordVersion: number) { + private async genPassword(rawPassword: any, passwordVersion: number) { if (passwordVersion == null || passwordVersion <= 1) { - return md5(plainPassword); + return md5(rawPassword); } const salt = bcrypt.genSaltSync(10); + const plainPassword = await this.buildPlainPassword(rawPassword); return bcrypt.hashSync(plainPassword, salt); } - async findOne(param) { + async findOne(param: any) { return this.repository.findOne({ where: param, }); } - async checkPassword( - rawPassword: any, - hashPassword: any, - passwordVersion: number - ) { + async checkPassword(rawPassword: any, hashPassword: any, passwordVersion: number) { if (passwordVersion == null || passwordVersion <= 1) { - return this.genPassword(rawPassword, passwordVersion) === hashPassword; + return (await this.genPassword(rawPassword, passwordVersion)) === hashPassword; } + const plainPassword = await this.buildPlainPassword(rawPassword); + return bcrypt.compareSync(plainPassword, hashPassword); + } - return bcrypt.compareSync(rawPassword, hashPassword); // true + async buildPlainPassword(rawPassword: string) { + const setting: SysInstallInfo = await this.sysSettingsService.getSetting(SysInstallInfo); + const prefixSiteId = setting.siteId.substring(1, 5); + return rawPassword + prefixSiteId; } /** @@ -147,17 +155,14 @@ export class UserService extends BaseService { status: 1, passwordVersion: 2, }); - newUser.password = this.genPassword( - newUser.password, - newUser.passwordVersion - ); + if (!newUser.password) { + newUser.password = randomText(6); + } + newUser.password = await this.genPassword(newUser.password, newUser.passwordVersion); await this.transaction(async txManager => { newUser = await txManager.save(newUser); - const userRole: UserRoleEntity = UserRoleEntity.of( - newUser.id, - Constants.role.defaultUser - ); + const userRole: UserRoleEntity = UserRoleEntity.of(newUser.id, Constants.role.defaultUser); await txManager.save(userRole); }); @@ -167,11 +172,7 @@ export class UserService extends BaseService { async changePassword(userId: any, form: any) { const user = await this.info(userId); - const passwordChecked = await this.checkPassword( - form.password, - user.password, - user.passwordVersion - ); + const passwordChecked = await this.checkPassword(form.password, user.password, user.passwordVersion); if (!passwordChecked) { throw new CommonException('原密码错误'); } diff --git a/packages/ui/certd-server/src/modules/pipeline/service/pipeline-service.ts b/packages/ui/certd-server/src/modules/pipeline/service/pipeline-service.ts index fc2c5824..508eeefb 100644 --- a/packages/ui/certd-server/src/modules/pipeline/service/pipeline-service.ts +++ b/packages/ui/certd-server/src/modules/pipeline/service/pipeline-service.ts @@ -137,15 +137,14 @@ export class PipelineService extends BaseService { name: `pipeline.${id}.trigger.once`, cron: null, job: async () => { - logger.info('job准备启动,当前定时器数量:', this.cron.getListSize()); + logger.info('用户手动启动job'); try { await this.run(id, null); } catch (e) { - logger.error('定时job执行失败:', e); + logger.error('手动job执行失败:', e); } }, }); - logger.info('定时器数量:', this.cron.getListSize()); } async delete(id: number) { @@ -182,7 +181,11 @@ export class PipelineService extends BaseService { cron: cron, job: async () => { logger.info('定时任务触发:', pipelineId, trigger.id); - await this.run(pipelineId, trigger.id); + try { + await this.run(pipelineId, trigger.id); + } catch (e) { + logger.error('定时job执行失败:', e); + } }, }); logger.info('当前定时器数量:', this.cron.getListSize()); @@ -244,17 +247,16 @@ export class PipelineService extends BaseService { const executor = runningTasks.get(historyId); if (executor) { await executor.cancel(); - } else { - const entity = await this.historyService.info(historyId); - if (entity == null) { - return; - } - const pipeline: Pipeline = JSON.parse(entity.pipeline); - pipeline.status.status = ResultType.canceled; - pipeline.status.result = ResultType.canceled; - const runtime = new RunHistory(historyId, null, pipeline); - await this.saveHistory(runtime); } + const entity = await this.historyService.info(historyId); + if (entity == null) { + return; + } + const pipeline: Pipeline = JSON.parse(entity.pipeline); + pipeline.status.status = ResultType.canceled; + pipeline.status.result = ResultType.canceled; + const runtime = new RunHistory(historyId, null, pipeline); + await this.saveHistory(runtime); } private getTriggerType(triggerId, pipeline) { diff --git a/packages/ui/certd-server/src/modules/system/controller/sys-settings-controller.ts b/packages/ui/certd-server/src/modules/system/controller/sys-settings-controller.ts index 489b8961..65b47387 100644 --- a/packages/ui/certd-server/src/modules/system/controller/sys-settings-controller.ts +++ b/packages/ui/certd-server/src/modules/system/controller/sys-settings-controller.ts @@ -1,15 +1,9 @@ -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 '../../../basic/crud-controller.js'; import { SysSettingsService } from '../service/sys-settings-service.js'; import { SysSettingsEntity } from '../entity/sys-settings.js'; +import { SysPublicSettings } from '../service/models.js'; +import * as _ from 'lodash-es'; /** */ @@ -74,7 +68,9 @@ export class SysSettingsController extends CrudController { // savePublicSettings @Post('/savePublicSettings', { summary: 'sys:settings:edit' }) async savePublicSettings(@Body(ALL) body) { - await this.service.savePublicSettings(body); + const setting = new SysPublicSettings(); + _.merge(setting, body); + await this.service.savePublicSettings(setting); return this.ok({}); } } diff --git a/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-ack-ingress/index.ts b/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-ack-ingress/index.ts index d479adc6..53d34d2b 100644 --- a/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-ack-ingress/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-ack-ingress/index.ts @@ -1,12 +1,4 @@ -import { - AbstractTaskPlugin, - IAccessService, - ILogger, - IsTaskPlugin, - RunStrategy, - TaskInput, - utils, -} from '@certd/pipeline'; +import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput, utils } from '@certd/pipeline'; // @ts-ignore import { ROAClient } from '@alicloud/pop-core'; import { AliyunAccess } from '../../access/index.js'; @@ -122,17 +114,10 @@ export class DeployCertToAliyunAckIngressPlugin extends AbstractTaskPlugin { } async execute(): Promise { console.log('开始部署证书到阿里云cdn'); - const { regionId, ingressClass, clusterId, isPrivateIpAddress, cert } = - this; - const access = (await this.accessService.getById( - this.accessId - )) as AliyunAccess; + const { regionId, ingressClass, clusterId, isPrivateIpAddress, cert } = this; + const access = (await this.accessService.getById(this.accessId)) as AliyunAccess; const client = this.getClient(access, regionId); - const kubeConfigStr = await this.getKubeConfig( - client, - clusterId, - isPrivateIpAddress - ); + const kubeConfigStr = await this.getKubeConfig(client, clusterId, isPrivateIpAddress); this.logger.info('kubeconfig已成功获取'); const k8sClient = new K8sClient(kubeConfigStr); @@ -224,11 +209,7 @@ export class DeployCertToAliyunAckIngressPlugin extends AbstractTaskPlugin { }); } - async getKubeConfig( - client: any, - clusterId: string, - isPrivateIpAddress = false - ) { + async getKubeConfig(client: any, clusterId: string, isPrivateIpAddress = false) { const httpMethod = 'GET'; const uriPath = `/k8s/${clusterId}/user_config`; const queries = { @@ -241,14 +222,7 @@ export class DeployCertToAliyunAckIngressPlugin extends AbstractTaskPlugin { const requestOption = {}; try { - const res = await client.request( - httpMethod, - uriPath, - queries, - body, - headers, - requestOption - ); + const res = await client.request(httpMethod, uriPath, queries, body, headers, requestOption); return res.config; } catch (e) { console.error('请求出错:', e); diff --git a/packages/ui/certd-server/src/plugins/plugin-demo/plugins/plugin-test.ts b/packages/ui/certd-server/src/plugins/plugin-demo/plugins/plugin-test.ts index 974a2ffb..bb5a5c74 100644 --- a/packages/ui/certd-server/src/plugins/plugin-demo/plugins/plugin-test.ts +++ b/packages/ui/certd-server/src/plugins/plugin-demo/plugins/plugin-test.ts @@ -1,5 +1,6 @@ import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput } from '@certd/pipeline'; import { CertInfo, CertReader } from '@certd/plugin-cert'; +import { K8sClient } from '@certd/lib-k8s'; @IsTaskPlugin({ name: 'demoTest', @@ -87,6 +88,8 @@ export class DemoTestPlugin extends AbstractTaskPlugin { this.logger.info('switch:', this.switch); this.logger.info('授权id:', accessId); //TODO 这里实现你要部署的执行方法 + + new K8sClient('111'); } } //TODO 这里实例化插件,进行注册