mirror of https://github.com/certd/certd
chore:
parent
14cdb54212
commit
d6b3142a02
|
@ -2,8 +2,8 @@ import crypto from 'crypto';
|
||||||
|
|
||||||
export class Encryptor {
|
export class Encryptor {
|
||||||
secretKey: Buffer;
|
secretKey: Buffer;
|
||||||
constructor(encryptSecret: string) {
|
constructor(encryptSecret: string, encoding: BufferEncoding = 'base64') {
|
||||||
this.secretKey = Buffer.from(encryptSecret, 'base64');
|
this.secretKey = Buffer.from(encryptSecret, encoding);
|
||||||
}
|
}
|
||||||
// 加密函数
|
// 加密函数
|
||||||
encrypt(text: string) {
|
encrypt(text: string) {
|
||||||
|
|
|
@ -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: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
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",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { request } from "/src/api/service";
|
import { request } from "/src/api/service";
|
||||||
|
|
||||||
export function createApi() {
|
export function createApi() {
|
||||||
const apiPrefix = "/open/cert";
|
const apiPrefix = "/open/key";
|
||||||
return {
|
return {
|
||||||
async GetList(query: any) {
|
async GetList(query: any) {
|
||||||
return await request({
|
return await request({
|
||||||
|
|
|
@ -3,6 +3,7 @@ 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";
|
import dayjs from "dayjs";
|
||||||
|
import { Modal } from "ant-design-vue";
|
||||||
|
|
||||||
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -35,6 +36,9 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
editRequest,
|
editRequest,
|
||||||
delRequest
|
delRequest
|
||||||
},
|
},
|
||||||
|
search: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
form: {
|
form: {
|
||||||
labelCol: {
|
labelCol: {
|
||||||
//固定label宽度
|
//固定label宽度
|
||||||
|
@ -50,15 +54,31 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
width: 600
|
width: 600
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actionbar: { show: false },
|
actionbar: {
|
||||||
|
buttons: {
|
||||||
|
add: {
|
||||||
|
text: "生成新的Key",
|
||||||
|
click() {
|
||||||
|
Modal.confirm({
|
||||||
|
title: "确认",
|
||||||
|
content: "确定要生成新的Key?",
|
||||||
|
async onOk() {
|
||||||
|
await api.AddObj({});
|
||||||
|
await crudExpose.doRefresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
rowHandle: {
|
rowHandle: {
|
||||||
width: 200,
|
width: 200,
|
||||||
fixed: "right",
|
fixed: "right",
|
||||||
buttons: {
|
buttons: {
|
||||||
view: { show: false },
|
view: { show: true },
|
||||||
copy: { show: false },
|
copy: { show: false },
|
||||||
edit: { show: false },
|
edit: { show: false },
|
||||||
remove: { show: false }
|
remove: { show: true }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
columns: {
|
columns: {
|
||||||
|
@ -79,125 +99,39 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
show: false
|
show: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// domain: {
|
keyId: {
|
||||||
// title: "主域名",
|
title: "KeyId",
|
||||||
// search: {
|
|
||||||
// show: true
|
|
||||||
// },
|
|
||||||
// type: "text",
|
|
||||||
// form: {
|
|
||||||
// show: false
|
|
||||||
// },
|
|
||||||
// column: {
|
|
||||||
// width: 180,
|
|
||||||
// sorter: true,
|
|
||||||
// component: {
|
|
||||||
// name: "fs-values-format"
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
domains: {
|
|
||||||
title: "全部域名",
|
|
||||||
search: {
|
search: {
|
||||||
show: false
|
show: false
|
||||||
},
|
},
|
||||||
|
form: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
type: "text",
|
type: "text",
|
||||||
form: {
|
|
||||||
rules: [{ required: true, message: "请输入域名" }]
|
|
||||||
},
|
|
||||||
column: {
|
column: {
|
||||||
width: 450,
|
width: 200,
|
||||||
sorter: true,
|
sorter: true
|
||||||
component: {
|
|
||||||
name: "fs-values-format",
|
|
||||||
color: "auto"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
domainCount: {
|
keySecret: {
|
||||||
title: "域名数量",
|
title: "KeySecret",
|
||||||
type: "number",
|
type: "text",
|
||||||
form: {
|
form: {
|
||||||
show: false
|
show: false
|
||||||
},
|
},
|
||||||
column: {
|
column: {
|
||||||
width: 120,
|
width: 550,
|
||||||
sorter: true,
|
sorter: true
|
||||||
show: false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pipeline.title": {
|
createTime: {
|
||||||
title: "已关联流水线",
|
title: "创建时间",
|
||||||
search: { show: false },
|
|
||||||
type: "link",
|
|
||||||
form: {
|
|
||||||
show: false
|
|
||||||
},
|
|
||||||
column: {
|
|
||||||
width: 280,
|
|
||||||
sorter: true,
|
|
||||||
component: {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
applyTime: {
|
|
||||||
title: "申请时间",
|
|
||||||
search: {
|
|
||||||
show: false
|
|
||||||
},
|
|
||||||
type: "datetime",
|
type: "datetime",
|
||||||
form: {
|
search: {
|
||||||
show: false
|
show: false
|
||||||
},
|
},
|
||||||
column: {
|
|
||||||
sorter: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
expiresTime: {
|
|
||||||
title: "过期时间",
|
|
||||||
search: {
|
|
||||||
show: true
|
|
||||||
},
|
|
||||||
type: "date",
|
|
||||||
form: {
|
form: {
|
||||||
show: false
|
show: false
|
||||||
},
|
|
||||||
column: {
|
|
||||||
sorter: true,
|
|
||||||
cellRender({ value }) {
|
|
||||||
if (!value) {
|
|
||||||
return "-";
|
|
||||||
}
|
|
||||||
const expireDate = dayjs(value).format("YYYY-MM-DD");
|
|
||||||
const leftDays = dayjs(value).diff(dayjs(), "day");
|
|
||||||
const color = leftDays < 20 ? "red" : "#389e0d";
|
|
||||||
const percent = (leftDays / 90) * 100;
|
|
||||||
return <a-progress title={expireDate + "过期"} percent={percent} strokeColor={color} format={(percent: number) => `${leftDays}天`} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
fromType: {
|
|
||||||
title: "来源",
|
|
||||||
search: {
|
|
||||||
show: true
|
|
||||||
},
|
|
||||||
type: "text",
|
|
||||||
form: { show: false },
|
|
||||||
column: {
|
|
||||||
width: 100,
|
|
||||||
sorter: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
certProvider: {
|
|
||||||
title: "证书颁发机构",
|
|
||||||
search: {
|
|
||||||
show: true
|
|
||||||
},
|
|
||||||
type: "text",
|
|
||||||
form: {
|
|
||||||
show: false
|
|
||||||
},
|
|
||||||
column: {
|
|
||||||
width: 400
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<fs-page>
|
<fs-page>
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="title">
|
<div class="title">开放接口密钥管理</div>
|
||||||
证书仓库
|
|
||||||
<span class="sub">从流水线生成的证书,后续将支持手动上传证书并部署</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
<fs-crud ref="crudRef" v-bind="crudBinding"> </fs-crud>
|
<fs-crud ref="crudRef" v-bind="crudBinding"> </fs-crud>
|
||||||
</fs-page>
|
</fs-page>
|
||||||
|
@ -16,7 +13,7 @@ import { useFs } from "@fast-crud/fast-crud";
|
||||||
import createCrudOptions from "./crud";
|
import createCrudOptions from "./crud";
|
||||||
import { createApi } from "./api";
|
import { createApi } from "./api";
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: "CertStore"
|
name: "OpenKey"
|
||||||
});
|
});
|
||||||
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: {} });
|
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: {} });
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ export class BaseOpenController extends BaseController {
|
||||||
const openKey: OpenKey = this.ctx.openKey;
|
const openKey: OpenKey = this.ctx.openKey;
|
||||||
if (openKey.encrypt) {
|
if (openKey.encrypt) {
|
||||||
const data = JSON.stringify(res);
|
const data = JSON.stringify(res);
|
||||||
const encryptor = new Encryptor(openKey.keySecret);
|
const encryptor = new Encryptor(openKey.keySecret, 'hex');
|
||||||
const encrypted = encryptor.encrypt(data);
|
const encrypted = encryptor.encrypt(data);
|
||||||
return this.ok(encrypted);
|
return this.ok(encrypted);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,8 @@ export class OpenKeyController extends CrudController<OpenKeyService> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('/add', { summary: Constants.per.authOnly })
|
@Post('/add', { summary: Constants.per.authOnly })
|
||||||
async add(@Body(ALL) bean: any) {
|
async add() {
|
||||||
|
const bean: any = {};
|
||||||
bean.userId = this.getUserId();
|
bean.userId = this.getUserId();
|
||||||
const res = await this.service.add(bean);
|
const res = await this.service.add(bean);
|
||||||
return this.ok(res);
|
return this.ok(res);
|
||||||
|
|
|
@ -27,30 +27,20 @@ export class OpenKeyService extends BaseService<OpenKeyEntity> {
|
||||||
return await super.page(pageReq);
|
return await super.page(pageReq);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getKey(userId: number) {
|
async add(bean: OpenKeyEntity) {
|
||||||
let entity = await this.getByUserId(userId);
|
return await this.generate(bean.userId);
|
||||||
if (entity) {
|
|
||||||
return {
|
|
||||||
keyId: entity.keyId,
|
|
||||||
keySecret: entity.keySecret,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
const keyId = utils.id.simpleNanoId(12) + '_key';
|
|
||||||
|
async generate(userId: number) {
|
||||||
|
const keyId = utils.id.simpleNanoId(18) + '_key';
|
||||||
const secretKey = crypto.randomBytes(32);
|
const secretKey = crypto.randomBytes(32);
|
||||||
const keySecret = secretKey.toString('base64');
|
const keySecret = Buffer.from(secretKey).toString('hex');
|
||||||
entity = new OpenKeyEntity();
|
const entity = new OpenKeyEntity();
|
||||||
entity.userId = userId;
|
entity.userId = userId;
|
||||||
entity.keyId = keyId;
|
entity.keyId = keyId;
|
||||||
entity.keySecret = keySecret;
|
entity.keySecret = keySecret;
|
||||||
await this.repository.save(entity);
|
await this.repository.save(entity);
|
||||||
return {
|
return entity;
|
||||||
keyId: entity.keyId,
|
|
||||||
keySecret: entity.keySecret,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private getByUserId(userId: number) {
|
|
||||||
return this.repository.findOne({ where: { userId } });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getByKeyId(keyId: string) {
|
async getByKeyId(keyId: string) {
|
||||||
|
|
Loading…
Reference in New Issue