mirror of https://github.com/certd/certd
Merge remote-tracking branch 'origin/v2-dev' into v2-dev
commit
b829bd1341
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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";
|
||||||
|
|
|
@ -12,6 +12,8 @@ export const Constants = {
|
||||||
authOnly: '_authOnly_',
|
authOnly: '_authOnly_',
|
||||||
//仅需要登录
|
//仅需要登录
|
||||||
loginOnly: '_authOnly_',
|
loginOnly: '_authOnly_',
|
||||||
|
|
||||||
|
open: '_open_',
|
||||||
},
|
},
|
||||||
res: {
|
res: {
|
||||||
serverError(message: string) {
|
serverError(message: string) {
|
||||||
|
@ -68,5 +70,33 @@ export const Constants = {
|
||||||
code: 10001,
|
code: 10001,
|
||||||
message: '对不起,预览环境不允许修改此数据',
|
message: '对不起,预览环境不允许修改此数据',
|
||||||
},
|
},
|
||||||
|
openKeyError: {
|
||||||
|
code: 20000,
|
||||||
|
message: 'ApiToken错误',
|
||||||
|
},
|
||||||
|
openKeySignError: {
|
||||||
|
code: 20001,
|
||||||
|
message: 'ApiToken签名错误',
|
||||||
|
},
|
||||||
|
openKeyExpiresError: {
|
||||||
|
code: 20002,
|
||||||
|
message: 'ApiToken时间戳错误',
|
||||||
|
},
|
||||||
|
openKeySignTypeError: {
|
||||||
|
code: 20003,
|
||||||
|
message: 'ApiToken签名类型不支持',
|
||||||
|
},
|
||||||
|
openParamError: {
|
||||||
|
code: 20010,
|
||||||
|
message: '请求参数错误',
|
||||||
|
},
|
||||||
|
openCertNotFound: {
|
||||||
|
code: 20011,
|
||||||
|
message: '证书不存在',
|
||||||
|
},
|
||||||
|
openCertNotReady: {
|
||||||
|
code: 20012,
|
||||||
|
message: '证书还未生成',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,10 +5,6 @@ import { BaseException } from './base-exception.js';
|
||||||
*/
|
*/
|
||||||
export class AuthException extends BaseException {
|
export class AuthException extends BaseException {
|
||||||
constructor(message) {
|
constructor(message) {
|
||||||
super(
|
super('AuthException', Constants.res.auth.code, message ? message : Constants.res.auth.message);
|
||||||
'AuthException',
|
|
||||||
Constants.res.auth.code,
|
|
||||||
message ? message : Constants.res.auth.message
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
* 异常基类
|
* 异常基类
|
||||||
*/
|
*/
|
||||||
export class BaseException extends Error {
|
export class BaseException extends Error {
|
||||||
status: number;
|
code: number;
|
||||||
constructor(name, code, message) {
|
constructor(name, code, message) {
|
||||||
super(message);
|
super(message);
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.status = code;
|
this.code = code;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,3 +8,9 @@ export class CommonException extends BaseException {
|
||||||
super('CommonException', Constants.res.error.code, message ? message : Constants.res.error.message);
|
super('CommonException', Constants.res.error.code, message ? message : Constants.res.error.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class CodeException extends BaseException {
|
||||||
|
constructor(res: { code: number; message: string }) {
|
||||||
|
super('CodeException', res.code, res.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ export class Result<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
static error(code = 1, msg) {
|
static error(code = 1, msg) {
|
||||||
return new Result(code, msg, null);
|
return new Result(code, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static success(msg, data?) {
|
static success(msg, data?) {
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
export * from './service/plus-service.js';
|
export * from './service/plus-service.js';
|
||||||
export * from './service/file-service.js';
|
export * from './service/file-service.js';
|
||||||
|
export * from './service/encryptor.js';
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
import crypto from 'crypto';
|
||||||
|
|
||||||
|
export class Encryptor {
|
||||||
|
secretKey: Buffer;
|
||||||
|
constructor(encryptSecret: string, encoding: BufferEncoding = 'base64') {
|
||||||
|
this.secretKey = Buffer.from(encryptSecret, encoding);
|
||||||
|
}
|
||||||
|
// 加密函数
|
||||||
|
encrypt(text: string) {
|
||||||
|
const iv = crypto.randomBytes(16); // 初始化向量
|
||||||
|
// const secretKey = crypto.randomBytes(32);
|
||||||
|
// const key = Buffer.from(secretKey);
|
||||||
|
const cipher = crypto.createCipheriv('aes-256-cbc', this.secretKey, iv);
|
||||||
|
let encrypted = cipher.update(text);
|
||||||
|
encrypted = Buffer.concat([encrypted, cipher.final()]);
|
||||||
|
return iv.toString('hex') + ':' + encrypted.toString('hex');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解密函数
|
||||||
|
decrypt(encryptedText: string) {
|
||||||
|
const textParts = encryptedText.split(':');
|
||||||
|
const iv = Buffer.from(textParts.shift(), 'hex');
|
||||||
|
const encrypted = Buffer.from(textParts.join(':'), 'hex');
|
||||||
|
const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(this.secretKey), iv);
|
||||||
|
let decrypted = decipher.update(encrypted);
|
||||||
|
decrypted = Buffer.concat([decrypted, decipher.final()]);
|
||||||
|
return decrypted.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
import { Init, Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
import { Init, Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||||
import crypto from 'crypto';
|
import { Encryptor, SysSecret, SysSettingsService } from '../../../system/index.js';
|
||||||
import { SysSecret, SysSettingsService } from '../../../system/index.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 授权
|
* 授权
|
||||||
|
@ -8,7 +7,7 @@ import { SysSecret, SysSettingsService } from '../../../system/index.js';
|
||||||
@Provide()
|
@Provide()
|
||||||
@Scope(ScopeEnum.Singleton)
|
@Scope(ScopeEnum.Singleton)
|
||||||
export class EncryptService {
|
export class EncryptService {
|
||||||
secretKey: Buffer;
|
encryptor: Encryptor;
|
||||||
|
|
||||||
@Inject()
|
@Inject()
|
||||||
sysSettingService: SysSettingsService;
|
sysSettingService: SysSettingsService;
|
||||||
|
@ -16,28 +15,16 @@ export class EncryptService {
|
||||||
@Init()
|
@Init()
|
||||||
async init() {
|
async init() {
|
||||||
const secret: SysSecret = await this.sysSettingService.getSecret();
|
const secret: SysSecret = await this.sysSettingService.getSecret();
|
||||||
this.secretKey = Buffer.from(secret.encryptSecret, 'base64');
|
this.encryptor = new Encryptor(secret.encryptSecret);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加密函数
|
// 加密函数
|
||||||
encrypt(text: string) {
|
encrypt(text: string) {
|
||||||
const iv = crypto.randomBytes(16); // 初始化向量
|
return this.encryptor.encrypt(text);
|
||||||
// const secretKey = crypto.randomBytes(32);
|
|
||||||
// const key = Buffer.from(secretKey);
|
|
||||||
const cipher = crypto.createCipheriv('aes-256-cbc', this.secretKey, iv);
|
|
||||||
let encrypted = cipher.update(text);
|
|
||||||
encrypted = Buffer.concat([encrypted, cipher.final()]);
|
|
||||||
return iv.toString('hex') + ':' + encrypted.toString('hex');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解密函数
|
// 解密函数
|
||||||
decrypt(encryptedText: string) {
|
decrypt(encryptedText: string) {
|
||||||
const textParts = encryptedText.split(':');
|
return this.encryptor.decrypt(encryptedText);
|
||||||
const iv = Buffer.from(textParts.shift(), 'hex');
|
|
||||||
const encrypted = Buffer.from(textParts.join(':'), 'hex');
|
|
||||||
const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(this.secretKey), iv);
|
|
||||||
let decrypted = decipher.update(encrypted);
|
|
||||||
decrypted = Buffer.concat([decrypted, decipher.final()]);
|
|
||||||
return decrypted.toString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.jks:jks格式证书文件,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}`);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 = {
|
||||||
|
|
|
@ -40,6 +40,17 @@ export const certdResources = [
|
||||||
cache: true
|
cache: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "证书仓库",
|
||||||
|
name: "CertStore",
|
||||||
|
path: "/certd/monitor/cert",
|
||||||
|
component: "/certd/monitor/cert/index.vue",
|
||||||
|
meta: {
|
||||||
|
icon: "ion:shield-checkmark-outline",
|
||||||
|
auth: true,
|
||||||
|
isMenu: true
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: "站点证书监控",
|
title: "站点证书监控",
|
||||||
name: "SiteCertMonitor",
|
name: "SiteCertMonitor",
|
||||||
|
@ -80,21 +91,6 @@ export const certdResources = [
|
||||||
auth: true
|
auth: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: "证书仓库",
|
|
||||||
name: "CertStore",
|
|
||||||
path: "/certd/monitor/cert",
|
|
||||||
component: "/certd/monitor/cert/index.vue",
|
|
||||||
meta: {
|
|
||||||
show: () => {
|
|
||||||
const settingStore = useSettingStore();
|
|
||||||
return settingStore.isPlus;
|
|
||||||
},
|
|
||||||
icon: "ion:shield-checkmark-outline",
|
|
||||||
auth: true,
|
|
||||||
isMenu: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: "授权管理",
|
title: "授权管理",
|
||||||
name: "AccessManager",
|
name: "AccessManager",
|
||||||
|
@ -106,6 +102,17 @@ export const certdResources = [
|
||||||
cache: true
|
cache: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "OpenKey",
|
||||||
|
name: "OpenKey",
|
||||||
|
path: "/certd/open/openkey",
|
||||||
|
component: "/certd/open/openkey/index.vue",
|
||||||
|
meta: {
|
||||||
|
icon: "ion:disc-outline",
|
||||||
|
auth: true,
|
||||||
|
cache: true
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: "通知设置",
|
title: "通知设置",
|
||||||
name: "NotificationManager",
|
name: "NotificationManager",
|
||||||
|
|
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -124,17 +126,40 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
show: false
|
show: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pipeline.title": {
|
expiresTime: {
|
||||||
title: "已关联流水线",
|
title: "过期时间",
|
||||||
search: { show: false },
|
search: {
|
||||||
type: "link",
|
show: true
|
||||||
|
},
|
||||||
|
type: "date",
|
||||||
form: {
|
form: {
|
||||||
show: false
|
show: false
|
||||||
},
|
},
|
||||||
column: {
|
column: {
|
||||||
width: 250,
|
|
||||||
sorter: true,
|
sorter: true,
|
||||||
component: {}
|
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}天`} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
certProvider: {
|
||||||
|
title: "证书颁发机构",
|
||||||
|
search: {
|
||||||
|
show: true
|
||||||
|
},
|
||||||
|
type: "text",
|
||||||
|
form: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
width: 200
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
applyTime: {
|
applyTime: {
|
||||||
|
@ -150,42 +175,17 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
sorter: true
|
sorter: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
expiresTime: {
|
"pipeline.title": {
|
||||||
title: "过期时间",
|
title: "已关联流水线",
|
||||||
search: {
|
search: { show: false },
|
||||||
show: true
|
type: "link",
|
||||||
},
|
|
||||||
type: "date",
|
|
||||||
form: {
|
form: {
|
||||||
show: false
|
show: false
|
||||||
},
|
},
|
||||||
column: {
|
column: {
|
||||||
sorter: true
|
width: 350,
|
||||||
}
|
sorter: true,
|
||||||
},
|
component: {}
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
import { request } from "/src/api/service";
|
||||||
|
|
||||||
|
export function createApi() {
|
||||||
|
const apiPrefix = "/open/key";
|
||||||
|
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 GetApiToken(id: number) {
|
||||||
|
return await request({
|
||||||
|
url: apiPrefix + "/getApiToken",
|
||||||
|
method: "post",
|
||||||
|
data: { id }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const pipelineGroupApi = createApi();
|
|
@ -0,0 +1,165 @@
|
||||||
|
// @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";
|
||||||
|
import { Modal } from "ant-design-vue";
|
||||||
|
import CertView from "/@/views/certd/pipeline/cert-view.vue";
|
||||||
|
import { useModal } from "/@/use/use-modal";
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
const model = useModal();
|
||||||
|
return {
|
||||||
|
crudOptions: {
|
||||||
|
request: {
|
||||||
|
pageRequest,
|
||||||
|
addRequest,
|
||||||
|
editRequest,
|
||||||
|
delRequest
|
||||||
|
},
|
||||||
|
search: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
labelCol: {
|
||||||
|
//固定label宽度
|
||||||
|
span: null,
|
||||||
|
style: {
|
||||||
|
width: "100px"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
col: {
|
||||||
|
span: 22
|
||||||
|
},
|
||||||
|
wrapper: {
|
||||||
|
width: 600
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actionbar: {
|
||||||
|
buttons: {
|
||||||
|
add: {
|
||||||
|
text: "生成新的Key",
|
||||||
|
click() {
|
||||||
|
Modal.confirm({
|
||||||
|
title: "确认",
|
||||||
|
content: "确定要生成新的Key?",
|
||||||
|
async onOk() {
|
||||||
|
await api.AddObj({});
|
||||||
|
await crudExpose.doRefresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rowHandle: {
|
||||||
|
width: 300,
|
||||||
|
fixed: "right",
|
||||||
|
buttons: {
|
||||||
|
view: { show: true },
|
||||||
|
copy: { show: false },
|
||||||
|
edit: { show: false },
|
||||||
|
remove: { show: true },
|
||||||
|
gen: {
|
||||||
|
text: "测试ApiToken",
|
||||||
|
async click({ row }) {
|
||||||
|
const apiToken = await api.GetApiToken(row.id);
|
||||||
|
|
||||||
|
model.success({
|
||||||
|
title: "ApiToken",
|
||||||
|
maskClosable: true,
|
||||||
|
okText: "确定",
|
||||||
|
width: 600,
|
||||||
|
content: () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div class={"m-10 p-10"}>测试ApiKey如下,您可以在3分钟内使用它进行开放接口请求测试</div>
|
||||||
|
<div class={"m-10 p-10"} style={{ border: "1px solid #333" }}>
|
||||||
|
<fs-copyable model-value={apiToken}></fs-copyable>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
columns: {
|
||||||
|
id: {
|
||||||
|
title: "ID",
|
||||||
|
key: "id",
|
||||||
|
type: "number",
|
||||||
|
search: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
width: 100,
|
||||||
|
editable: {
|
||||||
|
disabled: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
keyId: {
|
||||||
|
title: "KeyId",
|
||||||
|
search: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
type: "text",
|
||||||
|
column: {
|
||||||
|
width: 200,
|
||||||
|
sorter: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
keySecret: {
|
||||||
|
title: "KeySecret",
|
||||||
|
type: "text",
|
||||||
|
form: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
width: 550,
|
||||||
|
sorter: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
createTime: {
|
||||||
|
title: "创建时间",
|
||||||
|
type: "datetime",
|
||||||
|
search: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
<template>
|
||||||
|
<fs-page>
|
||||||
|
<template #header>
|
||||||
|
<div class="title">开放接口密钥管理</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: "OpenKey"
|
||||||
|
});
|
||||||
|
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: {} });
|
||||||
|
|
||||||
|
// 页面打开后获取列表数据
|
||||||
|
onMounted(() => {
|
||||||
|
crudExpose.doRefresh();
|
||||||
|
});
|
||||||
|
onActivated(() => {
|
||||||
|
crudExpose.doRefresh();
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -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");
|
|
@ -19,7 +19,6 @@ import * as libServer from '@certd/lib-server';
|
||||||
import * as commercial from '@certd/commercial-core';
|
import * as commercial from '@certd/commercial-core';
|
||||||
import * as upload from '@midwayjs/upload';
|
import * as upload from '@midwayjs/upload';
|
||||||
import { setLogger } from '@certd/acme-client';
|
import { setLogger } from '@certd/acme-client';
|
||||||
|
|
||||||
process.on('uncaughtException', error => {
|
process.on('uncaughtException', error => {
|
||||||
console.error('未捕获的异常:', error);
|
console.error('未捕获的异常:', error);
|
||||||
// 在这里可以添加日志记录、发送错误通知等操作
|
// 在这里可以添加日志记录、发送错误通知等操作
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { BaseController, Encryptor } from '@certd/lib-server';
|
||||||
|
import { OpenKey } from '../../modules/open/service/open-key-service.js';
|
||||||
|
|
||||||
|
export class BaseOpenController extends BaseController {
|
||||||
|
ok(res: any) {
|
||||||
|
const openKey: OpenKey = this.ctx.openKey;
|
||||||
|
if (openKey.encrypt) {
|
||||||
|
const data = JSON.stringify(res);
|
||||||
|
const encryptor = new Encryptor(openKey.keySecret, 'hex');
|
||||||
|
const encrypted = encryptor.encrypt(data);
|
||||||
|
return this.ok(encrypted);
|
||||||
|
}
|
||||||
|
return super.ok(res);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
import { ALL, Body, Controller, Get, Inject, Post, Provide, Query } from '@midwayjs/core';
|
||||||
|
import { CodeException, Constants, EncryptService } from '@certd/lib-server';
|
||||||
|
import { CertInfoService } from '../../../modules/monitor/service/cert-info-service.js';
|
||||||
|
import { CertInfo } from '@certd/plugin-cert';
|
||||||
|
import { OpenKey } from '../../../modules/open/service/open-key-service.js';
|
||||||
|
import { BaseOpenController } from '../base-open-controller.js';
|
||||||
|
|
||||||
|
export type CertGetReq = {
|
||||||
|
domains?: string;
|
||||||
|
certId: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
@Provide()
|
||||||
|
@Controller('/api/v1/cert')
|
||||||
|
export class OpenCertController extends BaseOpenController {
|
||||||
|
@Inject()
|
||||||
|
certInfoService: CertInfoService;
|
||||||
|
@Inject()
|
||||||
|
encryptService: EncryptService;
|
||||||
|
|
||||||
|
@Get('/get', { summary: Constants.per.open })
|
||||||
|
@Post('/get', { summary: Constants.per.open })
|
||||||
|
async get(@Body(ALL) bean: CertGetReq, @Query(ALL) query: CertGetReq) {
|
||||||
|
const openKey: OpenKey = this.ctx.openKey;
|
||||||
|
const userId = openKey.userId;
|
||||||
|
if (!userId) {
|
||||||
|
throw new CodeException(Constants.res.openKeyError);
|
||||||
|
}
|
||||||
|
|
||||||
|
const res: CertInfo = await this.certInfoService.getCertInfo({
|
||||||
|
userId,
|
||||||
|
domains: bean.domains || query.domains,
|
||||||
|
certId: bean.certId || query.certId,
|
||||||
|
});
|
||||||
|
return this.ok(res);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { Rule, RuleType } from '@midwayjs/validate';
|
import { Rule, RuleType } from '@midwayjs/validate';
|
||||||
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 { BaseController, Constants } from '@certd/lib-server';
|
import { BaseController, Constants } from '@certd/lib-server';
|
||||||
import { CodeService } from '../../modules/basic/service/code-service.js';
|
import { CodeService } from '../../../modules/basic/service/code-service.js';
|
||||||
import { EmailService } from '../../modules/basic/service/email-service.js';
|
import { EmailService } from '../../../modules/basic/service/email-service.js';
|
||||||
|
|
||||||
export class SmsCodeReq {
|
export class SmsCodeReq {
|
||||||
@Rule(RuleType.string().required())
|
@Rule(RuleType.string().required())
|
|
@ -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';
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -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';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 授权
|
* 授权
|
|
@ -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';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 授权
|
* 授权
|
|
@ -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;
|
|
@ -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';
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -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 = {
|
|
@ -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';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
|
@ -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';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
|
@ -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';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
|
@ -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';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
|
@ -0,0 +1,72 @@
|
||||||
|
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() {
|
||||||
|
const 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('/getApiToken', { summary: Constants.per.authOnly })
|
||||||
|
async getApiToken(@Query('id') id: number) {
|
||||||
|
await this.service.checkUserId(id, this.getUserId());
|
||||||
|
const token = await this.service.getApiToken(id);
|
||||||
|
return this.ok(token);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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';
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -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')
|
|
@ -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';
|
||||||
|
|
|
@ -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')
|
|
@ -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';
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -1,9 +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 { Constants, CrudController, SysSettingsService } from '@certd/lib-server';
|
import { Constants, CrudController, SysSettingsService } from '@certd/lib-server';
|
||||||
import { PipelineService } from '../../modules/pipeline/service/pipeline-service.js';
|
import { PipelineService } from '../../../modules/pipeline/service/pipeline-service.js';
|
||||||
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 { AuthService } from '../../modules/sys/authority/service/auth-service.js';
|
import { AuthService } from '../../../modules/sys/authority/service/auth-service.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 证书
|
* 证书
|
|
@ -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 { PipelineGroupService } from '../../modules/pipeline/service/pipeline-group-service.js';
|
import { PipelineGroupService } from '../../../modules/pipeline/service/pipeline-group-service.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通知
|
* 通知
|
|
@ -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 { BaseController, Constants } from '@certd/lib-server';
|
import { BaseController, Constants } from '@certd/lib-server';
|
||||||
import { PluginService } from '../../modules/plugin/service/plugin-service.js';
|
import { PluginService } from '../../../modules/plugin/service/plugin-service.js';
|
||||||
import { PluginConfigService } from '../../modules/plugin/service/plugin-config-service.js';
|
import { PluginConfigService } from '../../../modules/plugin/service/plugin-config-service.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 插件
|
* 插件
|
|
@ -1,11 +1,11 @@
|
||||||
import { Init, Inject, MidwayWebRouterService, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
import { Init, Inject, MidwayWebRouterService, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||||
import { IMidwayKoaContext, IWebMiddleware, NextFunction } from '@midwayjs/koa';
|
import { IMidwayKoaContext, IWebMiddleware, NextFunction } from '@midwayjs/koa';
|
||||||
import jwt from 'jsonwebtoken';
|
import jwt from 'jsonwebtoken';
|
||||||
import { Constants } from '@certd/lib-server';
|
import { Constants, SysPrivateSettings, SysSettingsService } from '@certd/lib-server';
|
||||||
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 { Next } from 'koa';
|
||||||
import { SysPrivateSettings } from '@certd/lib-server';
|
import { OpenKeyService } from '../modules/open/service/open-key-service.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 权限校验
|
* 权限校验
|
||||||
|
@ -18,6 +18,8 @@ export class AuthorityMiddleware implements IWebMiddleware {
|
||||||
@Inject()
|
@Inject()
|
||||||
authService: AuthService;
|
authService: AuthService;
|
||||||
@Inject()
|
@Inject()
|
||||||
|
openKeyService: OpenKeyService;
|
||||||
|
@Inject()
|
||||||
sysSettingsService: SysSettingsService;
|
sysSettingsService: SysSettingsService;
|
||||||
|
|
||||||
secret: string;
|
secret: string;
|
||||||
|
@ -48,6 +50,10 @@ export class AuthorityMiddleware implements IWebMiddleware {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (permission === Constants.per.open) {
|
||||||
|
return this.doOpenHandler(ctx, next);
|
||||||
|
}
|
||||||
|
|
||||||
let token = ctx.get('Authorization') || '';
|
let token = ctx.get('Authorization') || '';
|
||||||
token = token.replace('Bearer ', '').trim();
|
token = token.replace('Bearer ', '').trim();
|
||||||
if (!token) {
|
if (!token) {
|
||||||
|
@ -79,4 +85,20 @@ export class AuthorityMiddleware implements IWebMiddleware {
|
||||||
await next();
|
await next();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async doOpenHandler(ctx: IMidwayKoaContext, next: Next) {
|
||||||
|
//开放接口
|
||||||
|
const openKey = ctx.get('x-api-token') || '';
|
||||||
|
if (!openKey) {
|
||||||
|
ctx.status = 401;
|
||||||
|
ctx.body = Constants.res.auth;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//校验 openKey
|
||||||
|
const openKeyRes = await this.openKeyService.verifyOpenKey(openKey);
|
||||||
|
ctx.user = { id: openKeyRes.userId };
|
||||||
|
ctx.openKey = openKeyRes;
|
||||||
|
await next();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export * from "./entity/site-info.js";
|
export * from './entity/site-info.js';
|
||||||
export * from "./entity/cert-info.js";
|
export * from './entity/cert-info.js';
|
||||||
|
|
||||||
export * from "./service/cert-info-service.js";
|
export * from './service/cert-info-service.js';
|
||||||
export * from "./service/site-info-service.js";
|
export * from './service/site-info-service.js';
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
import { Provide } from '@midwayjs/core';
|
import { Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||||
import { BaseService, 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';
|
||||||
import { CertInfoEntity } from '../entity/cert-info.js';
|
import { CertInfoEntity } from '../entity/cert-info.js';
|
||||||
|
import { utils } from '@certd/basic';
|
||||||
|
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>;
|
||||||
|
@ -68,4 +71,81 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
|
||||||
pipelineId: id,
|
pipelineId: id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getCertInfo(params: { domains?: string; certId?: number; userId: number }) {
|
||||||
|
const { domains, certId, userId } = params;
|
||||||
|
if (certId) {
|
||||||
|
return await this.getCertInfoById({ id: certId, userId });
|
||||||
|
}
|
||||||
|
return await this.getCertInfoByDomains({
|
||||||
|
domains,
|
||||||
|
userId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getCertInfoByDomains(params: { domains: string; userId: number }) {
|
||||||
|
const { domains, userId } = params;
|
||||||
|
if (!domains) {
|
||||||
|
throw new CodeException(Constants.res.openCertNotFound);
|
||||||
|
}
|
||||||
|
const domainArr = domains.split(',');
|
||||||
|
|
||||||
|
const list = await this.find({
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
domains: true,
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
userId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
//遍历查找
|
||||||
|
const matched = list.find(item => {
|
||||||
|
const itemDomains = item.domains.split(',');
|
||||||
|
return utils.domain.match(domainArr, itemDomains);
|
||||||
|
});
|
||||||
|
if (!matched) {
|
||||||
|
throw new CodeException(Constants.res.openCertNotFound);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await this.getCertInfoById({ id: matched.id, userId: userId });
|
||||||
|
}
|
||||||
|
|
||||||
|
async getCertInfoById(req: { id: number; userId: number }) {
|
||||||
|
const entity = await this.info(req.id);
|
||||||
|
if (!entity || entity.userId !== req.userId) {
|
||||||
|
throw new CodeException(Constants.res.openCertNotFound);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!entity.certInfo) {
|
||||||
|
throw new CodeException(Constants.res.openCertNotReady);
|
||||||
|
}
|
||||||
|
const certInfo = JSON.parse(entity.certInfo) as CertInfo;
|
||||||
|
const certReader = new CertReader(certInfo);
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>;
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
|
|
||||||
|
@Entity('cd_open_key')
|
||||||
|
export class OpenKeyEntity {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column({ name: 'user_id', comment: '用户id' })
|
||||||
|
userId: number;
|
||||||
|
|
||||||
|
@Column({ name: 'key_id', comment: 'keyId' })
|
||||||
|
keyId: string;
|
||||||
|
|
||||||
|
@Column({ name: 'key_secret', comment: 'keySecret' })
|
||||||
|
keySecret: string;
|
||||||
|
|
||||||
|
@Column({ name: 'create_time', comment: '创建时间', default: () => 'CURRENT_TIMESTAMP' })
|
||||||
|
createTime: Date;
|
||||||
|
|
||||||
|
@Column({ name: 'update_time', comment: '修改时间', default: () => 'CURRENT_TIMESTAMP' })
|
||||||
|
updateTime: Date;
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
import { Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||||
|
import { BaseService, Constants, CodeException, PageReq } from '@certd/lib-server';
|
||||||
|
import { InjectEntityModel } from '@midwayjs/typeorm';
|
||||||
|
import { Repository } from 'typeorm';
|
||||||
|
import { OpenKeyEntity } from '../entity/open-key.js';
|
||||||
|
import { utils } from '@certd/basic';
|
||||||
|
import crypto from 'crypto';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
|
export type OpenKey = {
|
||||||
|
userId: number;
|
||||||
|
keyId: string;
|
||||||
|
keySecret: string;
|
||||||
|
encrypt: boolean;
|
||||||
|
};
|
||||||
|
@Provide()
|
||||||
|
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||||
|
export class OpenKeyService extends BaseService<OpenKeyEntity> {
|
||||||
|
@InjectEntityModel(OpenKeyEntity)
|
||||||
|
repository: Repository<OpenKeyEntity>;
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
getRepository() {
|
||||||
|
return this.repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
async page(pageReq: PageReq<OpenKeyEntity>) {
|
||||||
|
return await super.page(pageReq);
|
||||||
|
}
|
||||||
|
|
||||||
|
async add(bean: OpenKeyEntity) {
|
||||||
|
return await this.generate(bean.userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
async generate(userId: number) {
|
||||||
|
const keyId = utils.id.simpleNanoId(18) + '_key';
|
||||||
|
const secretKey = crypto.randomBytes(32);
|
||||||
|
const keySecret = Buffer.from(secretKey).toString('hex');
|
||||||
|
const entity = new OpenKeyEntity();
|
||||||
|
entity.userId = userId;
|
||||||
|
entity.keyId = keyId;
|
||||||
|
entity.keySecret = keySecret;
|
||||||
|
await this.repository.save(entity);
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getByKeyId(keyId: string) {
|
||||||
|
return this.repository.findOne({ where: { keyId } });
|
||||||
|
}
|
||||||
|
|
||||||
|
async verifyOpenKey(openKey: string): Promise<OpenKey> {
|
||||||
|
// openkey 组成,content = base64({keyId,t,encrypt,signType}) ,sign = md5({keyId,t,encrypt,signType}secret) , key = content.sign
|
||||||
|
const [content, sign] = openKey.split('.');
|
||||||
|
const contentJson = Buffer.from(content, 'base64').toString();
|
||||||
|
const { keyId, t, encrypt, signType } = JSON.parse(contentJson);
|
||||||
|
// 正负不超过3分钟 ,timestamps单位为秒
|
||||||
|
if (Math.abs(Number(t) - Math.floor(Date.now() / 1000)) > 180) {
|
||||||
|
throw new CodeException(Constants.res.openKeyExpiresError);
|
||||||
|
}
|
||||||
|
|
||||||
|
const entity = await this.getByKeyId(keyId);
|
||||||
|
if (!entity) {
|
||||||
|
throw new Error('openKey不存在');
|
||||||
|
}
|
||||||
|
const secret = entity.keySecret;
|
||||||
|
let computedSign = '';
|
||||||
|
if (signType === 'md5') {
|
||||||
|
computedSign = utils.hash.md5(contentJson + secret);
|
||||||
|
} else if (signType === 'sha256') {
|
||||||
|
computedSign = utils.hash.sha256(contentJson + secret);
|
||||||
|
} else {
|
||||||
|
throw new CodeException(Constants.res.openKeySignTypeError);
|
||||||
|
}
|
||||||
|
if (Buffer.from(computedSign).toString('base64') !== sign) {
|
||||||
|
throw new CodeException(Constants.res.openKeySignError);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!entity.userId) {
|
||||||
|
throw new CodeException(Constants.res.openKeyError);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
userId: entity.userId,
|
||||||
|
keyId: entity.keyId,
|
||||||
|
keySecret: entity.keySecret,
|
||||||
|
encrypt: encrypt,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async getApiToken(id: number) {
|
||||||
|
const entity = await this.repository.findOne({ where: { id } });
|
||||||
|
if (!entity) {
|
||||||
|
throw new Error('id不存在');
|
||||||
|
}
|
||||||
|
const { keyId, keySecret } = entity;
|
||||||
|
const openKey = {
|
||||||
|
keyId,
|
||||||
|
t: dayjs().unix(),
|
||||||
|
encrypt: false,
|
||||||
|
signType: 'md5',
|
||||||
|
};
|
||||||
|
const content = JSON.stringify(openKey);
|
||||||
|
const sign = utils.hash.md5(content + keySecret);
|
||||||
|
return Buffer.from(content).toString('base64') + '.' + Buffer.from(sign).toString('base64');
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue