v2
xiaojunnuo 2025-01-15 01:26:23 +08:00
parent 14cdb54212
commit d6b3142a02
8 changed files with 77 additions and 148 deletions

View File

@ -2,8 +2,8 @@ import crypto from 'crypto';
export class Encryptor {
secretKey: Buffer;
constructor(encryptSecret: string) {
this.secretKey = Buffer.from(encryptSecret, 'base64');
constructor(encryptSecret: string, encoding: BufferEncoding = 'base64') {
this.secretKey = Buffer.from(encryptSecret, encoding);
}
// 加密函数
encrypt(text: string) {

View File

@ -40,6 +40,17 @@ export const certdResources = [
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: "站点证书监控",
name: "SiteCertMonitor",
@ -80,21 +91,6 @@ export const certdResources = [
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: "授权管理",
name: "AccessManager",
@ -106,6 +102,17 @@ export const certdResources = [
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: "通知设置",
name: "NotificationManager",

View File

@ -1,7 +1,7 @@
import { request } from "/src/api/service";
export function createApi() {
const apiPrefix = "/open/cert";
const apiPrefix = "/open/key";
return {
async GetList(query: any) {
return await request({

View File

@ -3,6 +3,7 @@ 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";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const { t } = useI18n();
@ -35,6 +36,9 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
editRequest,
delRequest
},
search: {
show: false
},
form: {
labelCol: {
//固定label宽度
@ -50,15 +54,31 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
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: {
width: 200,
fixed: "right",
buttons: {
view: { show: false },
view: { show: true },
copy: { show: false },
edit: { show: false },
remove: { show: false }
remove: { show: true }
}
},
columns: {
@ -79,125 +99,39 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
show: false
}
},
// domain: {
// title: "主域名",
// search: {
// show: true
// },
// type: "text",
// form: {
// show: false
// },
// column: {
// width: 180,
// sorter: true,
// component: {
// name: "fs-values-format"
// }
// }
// },
domains: {
title: "全部域名",
keyId: {
title: "KeyId",
search: {
show: false
},
form: {
show: false
},
type: "text",
form: {
rules: [{ required: true, message: "请输入域名" }]
},
column: {
width: 450,
sorter: true,
component: {
name: "fs-values-format",
color: "auto"
}
width: 200,
sorter: true
}
},
domainCount: {
title: "域名数量",
type: "number",
keySecret: {
title: "KeySecret",
type: "text",
form: {
show: false
},
column: {
width: 120,
sorter: true,
show: false
width: 550,
sorter: true
}
},
"pipeline.title": {
title: "已关联流水线",
search: { show: false },
type: "link",
form: {
show: false
},
column: {
width: 280,
sorter: true,
component: {}
}
},
applyTime: {
title: "申请时间",
search: {
show: false
},
createTime: {
title: "创建时间",
type: "datetime",
form: {
search: {
show: false
},
column: {
sorter: true
}
},
expiresTime: {
title: "过期时间",
search: {
show: true
},
type: "date",
form: {
show: false
},
column: {
sorter: true,
cellRender({ value }) {
if (!value) {
return "-";
}
const expireDate = dayjs(value).format("YYYY-MM-DD");
const leftDays = dayjs(value).diff(dayjs(), "day");
const color = leftDays < 20 ? "red" : "#389e0d";
const percent = (leftDays / 90) * 100;
return <a-progress title={expireDate + "过期"} percent={percent} strokeColor={color} format={(percent: number) => `${leftDays}`} />;
}
}
},
fromType: {
title: "来源",
search: {
show: true
},
type: "text",
form: { show: false },
column: {
width: 100,
sorter: true
}
},
certProvider: {
title: "证书颁发机构",
search: {
show: true
},
type: "text",
form: {
show: false
},
column: {
width: 400
}
}
}

View File

@ -1,10 +1,7 @@
<template>
<fs-page>
<template #header>
<div class="title">
证书仓库
<span class="sub">从流水线生成的证书后续将支持手动上传证书并部署</span>
</div>
<div class="title">开放接口密钥管理</div>
</template>
<fs-crud ref="crudRef" v-bind="crudBinding"> </fs-crud>
</fs-page>
@ -16,7 +13,7 @@ import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import { createApi } from "./api";
defineOptions({
name: "CertStore"
name: "OpenKey"
});
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: {} });

View File

@ -6,7 +6,7 @@ export class BaseOpenController extends BaseController {
const openKey: OpenKey = this.ctx.openKey;
if (openKey.encrypt) {
const data = JSON.stringify(res);
const encryptor = new Encryptor(openKey.keySecret);
const encryptor = new Encryptor(openKey.keySecret, 'hex');
const encrypted = encryptor.encrypt(data);
return this.ok(encrypted);
}

View File

@ -37,7 +37,8 @@ export class OpenKeyController extends CrudController<OpenKeyService> {
}
@Post('/add', { summary: Constants.per.authOnly })
async add(@Body(ALL) bean: any) {
async add() {
const bean: any = {};
bean.userId = this.getUserId();
const res = await this.service.add(bean);
return this.ok(res);

View File

@ -27,30 +27,20 @@ export class OpenKeyService extends BaseService<OpenKeyEntity> {
return await super.page(pageReq);
}
async getKey(userId: number) {
let entity = await this.getByUserId(userId);
if (entity) {
return {
keyId: entity.keyId,
keySecret: entity.keySecret,
};
}
const keyId = utils.id.simpleNanoId(12) + '_key';
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 = secretKey.toString('base64');
entity = new OpenKeyEntity();
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 {
keyId: entity.keyId,
keySecret: entity.keySecret,
};
}
private getByUserId(userId: number) {
return this.repository.findOne({ where: { userId } });
return entity;
}
async getByKeyId(keyId: string) {