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

View File

@ -122,3 +122,11 @@ export async function GetCert(pipelineId: number): Promise<CertInfo> {
params: { id: pipelineId }, 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> </template>
<script lang="tsx" setup> <script lang="tsx" setup>
import { computed, inject } from "vue"; import { computed, inject, watch, ref } from "vue";
import { useCertUpload } from "./use"; import { useCertUpload } from "./use";
import { getAllDomainsFromCrt } from "/@/views/certd/pipeline/utils"; import { getAllDomainsFromCrt } from "/@/views/certd/pipeline/utils";
@ -27,19 +27,36 @@ const emit = defineEmits(["updated", "update:modelValue"]);
const { openUpdateCertDialog } = useCertUpload(); const { openUpdateCertDialog } = useCertUpload();
const domain = computed(() => { const domainsRef = ref([]);
if (!props.modelValue?.crt) {
return "";
}
const domains = getAllDomainsFromCrt(props.modelValue?.crt);
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); emit("update:modelValue", res.uploadCert);
const domains = getAllDomainsFromCrt(res.uploadCert.crt);
emit("updated", { domains });
} }
const pipeline: any = inject("pipeline"); const pipeline: any = inject("pipeline");

View File

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

View File

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

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 { 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';
import {CertReader} from "@certd/plugin-cert";
@Provide() @Provide()
@Controller('/api/pi/cert') @Controller('/api/pi/cert')
@ -18,4 +19,14 @@ export class CertController extends BaseController {
const privateVars = await this.storeService.getPipelinePrivateVars(id); const privateVars = await this.storeService.getPipelinePrivateVars(id);
return this.ok(privateVars.cert); 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);
}
} }