fix: 上传商用证书,直接粘贴文本报错的问题;修复无法上传ec加密证书的bug

pull/409/head
xiaojunnuo 2025-04-19 15:00:34 +08:00
parent 0e07ae6ce8
commit 5750bb7067
6 changed files with 59 additions and 52 deletions

View File

@ -1,7 +1,7 @@
<template>
<div class="pem-input">
<FileInput v-bind="fileInput" class="mb-5" type="primary" text="选择文件" @change="onChange" />
<a-textarea v-bind="textarea" v-model:value="textRef"></a-textarea>
<a-textarea v-bind="textarea" :value="modelValue" @update:value="emitValue"></a-textarea>
</div>
</template>
@ -17,7 +17,6 @@ const props = defineProps<{
}>();
const emit = defineEmits(["update:modelValue"]);
const textRef = ref();
function emitValue(value: string) {
emit("update:modelValue", value);
@ -39,16 +38,6 @@ function onChange(e: any) {
};
fileReader.readAsText(file); //
}
watch(
() => props.modelValue,
value => {
textRef.value = value;
},
{
immediate: true,
}
);
</script>
<style lang="less">

View File

@ -122,3 +122,11 @@ export async function GetCert(pipelineId: number): Promise<CertInfo> {
params: { id: pipelineId },
});
}
export async function ReadCertDetail(crt: string): Promise<any> {
return await request({
url: certApiPrefix + "/readCertDetail",
method: "post",
data: { crt },
});
}

View File

@ -8,7 +8,7 @@
</template>
<script lang="tsx" setup>
import { computed, inject } from "vue";
import { computed, inject, watch, ref } from "vue";
import { useCertUpload } from "./use";
import { getAllDomainsFromCrt } from "/@/views/certd/pipeline/utils";
@ -27,19 +27,36 @@ const emit = defineEmits(["updated", "update:modelValue"]);
const { openUpdateCertDialog } = useCertUpload();
const domain = computed(() => {
if (!props.modelValue?.crt) {
return "";
}
const domains = getAllDomainsFromCrt(props.modelValue?.crt);
const domainsRef = ref([]);
return domains[0];
watch(
() => {
return props.modelValue?.crt;
},
async crt => {
if (crt) {
domainsRef.value = await getAllDomainsFromCrt(crt);
} else {
domainsRef.value = [];
}
emit("updated", { domains: domainsRef.value });
},
{
immediate: true,
}
);
const domain = computed(() => {
if (domainsRef.value && domainsRef.value.length > 0) {
return domainsRef.value[0];
}
return "";
});
function onUpdated(res: { uploadCert: any }) {
async function onUpdated(res: { uploadCert: any }) {
emit("update:modelValue", res.uploadCert);
const domains = getAllDomainsFromCrt(res.uploadCert.crt);
emit("updated", { domains });
}
const pipeline: any = inject("pipeline");

View File

@ -135,7 +135,7 @@ export function useCertUpload() {
},
async doSubmit({ form }: any) {
const cert = form.uploadCert;
const domains = getAllDomainsFromCrt(cert.crt);
const domains = await getAllDomainsFromCrt(cert.crt);
const notifications = [];
if (form.notification != null) {

View File

@ -2,8 +2,7 @@ import { forEach } from "lodash-es";
import { mySuiteApi } from "/@/views/certd/suite/mine/api";
import { notification } from "ant-design-vue";
import { useSettingStore } from "/@/store/settings";
//@ts-ignore
import forge from "node-forge";
import { ReadCertDetail } from "./api";
export function eachStages(list: any[], exec: (item: any, runnableType: string) => void, runnableType: string = "stage") {
if (!list || list.length <= 0) {
return;
@ -70,33 +69,16 @@ export async function checkPipelineLimit() {
}
}
export function readCertDetail(crt: string) {
const detail = forge.pki.certificateFromPem(crt);
const expires = detail.notAfter;
return { detail, expires };
export async function readCertDetail(crt: string) {
return await ReadCertDetail(crt);
}
export function getAllDomainsFromCrt(crt: string) {
const { detail } = readCertDetail(crt);
const domains = [];
// 1. 提取SAN中的DNS名称
const sanExtension = detail.extensions.find((ext: any) => ext.name === "subjectAltName");
if (sanExtension) {
sanExtension.altNames.forEach((altName: any) => {
if (altName.type === 2) {
// type=2 表示DNS名称
domains.push(altName.value);
export async function getAllDomainsFromCrt(crt: string) {
const { detail } = await readCertDetail(crt);
const altNames = detail.domains.altNames;
const commonName = detail.domains.commonName;
if (altNames.includes(commonName)) {
return altNames;
}
});
}
// 2. 如果没有SAN回退到CN通用名称
if (domains.length === 0) {
const cnAttr = detail.subject.attributes.find((attr: any) => attr.name === "commonName");
if (cnAttr) {
domains.push(cnAttr.value);
}
}
return domains;
return [commonName, ...altNames];
}

View File

@ -1,7 +1,8 @@
import { Controller, Inject, Post, Provide, Query } from '@midwayjs/core';
import {Body, Controller, Inject, Post, Provide, Query} from '@midwayjs/core';
import { PipelineService } from '../../../modules/pipeline/service/pipeline-service.js';
import { BaseController, Constants } from '@certd/lib-server';
import { StorageService } from '../../../modules/pipeline/service/storage-service.js';
import {CertReader} from "@certd/plugin-cert";
@Provide()
@Controller('/api/pi/cert')
@ -18,4 +19,14 @@ export class CertController extends BaseController {
const privateVars = await this.storeService.getPipelinePrivateVars(id);
return this.ok(privateVars.cert);
}
@Post('/readCertDetail', { summary: Constants.per.authOnly })
async readCertDetail(@Body('crt') crt: string) {
if (!crt) {
throw new Error('crt is required');
}
const certDetail = CertReader.readCertDetail(crt)
return this.ok(certDetail);
}
}