mirror of https://github.com/certd/certd
perf: 支持p7b证书格式
parent
70fcdc9ebb
commit
d9f4a5793d
|
@ -48,6 +48,7 @@ export type CertInfo = {
|
|||
der?: string;
|
||||
jks?: string;
|
||||
one?: string;
|
||||
p7b?: string;
|
||||
};
|
||||
export type SSLProvider = "letsencrypt" | "google" | "zerossl";
|
||||
export type PrivateKeyType = "rsa_1024" | "rsa_2048" | "rsa_3072" | "rsa_4096" | "ec_256" | "ec_384" | "ec_521";
|
||||
|
|
|
@ -125,6 +125,10 @@ export abstract class CertApplyBaseConvertPlugin extends AbstractTaskPlugin {
|
|||
cert.jks = res.jks;
|
||||
}
|
||||
|
||||
if (cert.p7b == null && res.p7b) {
|
||||
cert.p7b = res.p7b;
|
||||
}
|
||||
|
||||
this.logger.info("转换证书格式成功");
|
||||
} catch (e) {
|
||||
this.logger.error("转换证书格式失败", e);
|
||||
|
@ -150,6 +154,7 @@ export abstract class CertApplyBaseConvertPlugin extends AbstractTaskPlugin {
|
|||
zip.file("intermediate.crt", cert.ic);
|
||||
zip.file("origin.crt", cert.oc);
|
||||
zip.file("one.pem", cert.one);
|
||||
zip.file("cert.p7b", cert.p7b);
|
||||
if (cert.pfx) {
|
||||
zip.file("cert.pfx", Buffer.from(cert.pfx, "base64"));
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ export type CertReaderHandleContext = {
|
|||
tmpIcPath?: string;
|
||||
tmpJksPath?: string;
|
||||
tmpOnePath?: string;
|
||||
tmpP7bPath?: string;
|
||||
};
|
||||
export type CertReaderHandle = (ctx: CertReaderHandleContext) => Promise<void>;
|
||||
export type HandleOpts = { logger: ILogger; handle: CertReaderHandle };
|
||||
|
@ -124,7 +125,7 @@ export class CertReader {
|
|||
return domain;
|
||||
}
|
||||
|
||||
saveToFile(type: "crt" | "key" | "pfx" | "der" | "oc" | "one" | "ic" | "jks", filepath?: string) {
|
||||
saveToFile(type: "crt" | "key" | "pfx" | "der" | "oc" | "one" | "ic" | "jks" | "p7b", filepath?: string) {
|
||||
if (!this.cert[type]) {
|
||||
return;
|
||||
}
|
||||
|
@ -138,7 +139,7 @@ export class CertReader {
|
|||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
if (type === "crt" || type === "key" || type === "ic" || type === "oc" || type === "one") {
|
||||
if (type === "crt" || type === "key" || type === "ic" || type === "oc" || type === "one" || type === "p7b") {
|
||||
fs.writeFileSync(filepath, this.cert[type]);
|
||||
} else {
|
||||
fs.writeFileSync(filepath, Buffer.from(this.cert[type], "base64"));
|
||||
|
@ -157,17 +158,19 @@ export class CertReader {
|
|||
const tmpDerPath = this.saveToFile("der");
|
||||
const tmpJksPath = this.saveToFile("jks");
|
||||
const tmpOnePath = this.saveToFile("one");
|
||||
const tmpP7bPath = this.saveToFile("p7b");
|
||||
logger.info("本地文件写入成功");
|
||||
try {
|
||||
return await opts.handle({
|
||||
reader: this,
|
||||
tmpCrtPath: tmpCrtPath,
|
||||
tmpKeyPath: tmpKeyPath,
|
||||
tmpPfxPath: tmpPfxPath,
|
||||
tmpDerPath: tmpDerPath,
|
||||
tmpIcPath: tmpIcPath,
|
||||
tmpJksPath: tmpJksPath,
|
||||
tmpOcPath: tmpOcPath,
|
||||
tmpCrtPath,
|
||||
tmpKeyPath,
|
||||
tmpPfxPath,
|
||||
tmpDerPath,
|
||||
tmpIcPath,
|
||||
tmpJksPath,
|
||||
tmpOcPath,
|
||||
tmpP7bPath,
|
||||
tmpOnePath,
|
||||
});
|
||||
} catch (err) {
|
||||
|
@ -189,6 +192,7 @@ export class CertReader {
|
|||
removeFile(tmpIcPath);
|
||||
removeFile(tmpJksPath);
|
||||
removeFile(tmpOnePath);
|
||||
removeFile(tmpP7bPath);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,11 +18,13 @@ export class CertConverter {
|
|||
pfx: string;
|
||||
der: string;
|
||||
jks: string;
|
||||
p7b: string;
|
||||
}> {
|
||||
const certReader = new CertReader(opts.cert);
|
||||
let pfx: string;
|
||||
let der: string;
|
||||
let jks: string;
|
||||
let p7b: string;
|
||||
const handle = async (ctx: CertReaderHandleContext) => {
|
||||
// 调用openssl 转pfx
|
||||
pfx = await this.convertPfx(ctx, opts.pfxPassword, opts.pfxArgs);
|
||||
|
@ -31,6 +33,8 @@ export class CertConverter {
|
|||
der = await this.convertDer(ctx);
|
||||
|
||||
jks = await this.convertJks(ctx, opts.pfxPassword);
|
||||
|
||||
p7b = await this.convertP7b(ctx);
|
||||
};
|
||||
|
||||
await certReader.readCertFile({ logger: this.logger, handle });
|
||||
|
@ -39,6 +43,7 @@ export class CertConverter {
|
|||
pfx,
|
||||
der,
|
||||
jks,
|
||||
p7b,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -95,6 +100,23 @@ export class CertConverter {
|
|||
return derCert;
|
||||
}
|
||||
|
||||
async convertP7b(opts: CertReaderHandleContext) {
|
||||
const { tmpCrtPath } = opts;
|
||||
const p7bPath = path.join(os.tmpdir(), "/certd/tmp/", Math.floor(Math.random() * 1000000) + `_cert.p7b`);
|
||||
const dir = path.dirname(p7bPath);
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
//openssl crl2pkcs7 -nocrl \
|
||||
// -certfile your_domain.crt \
|
||||
// -certfile intermediate.crt \
|
||||
// -out chain.p7b
|
||||
await this.exec(`openssl crl2pkcs7 -nocrl -certfile ${tmpCrtPath} -out ${p7bPath}`);
|
||||
const fileBuffer = fs.readFileSync(p7bPath);
|
||||
const p7bCert = fileBuffer.toString();
|
||||
fs.unlinkSync(p7bPath);
|
||||
return p7bCert;
|
||||
}
|
||||
async convertJks(opts: CertReaderHandleContext, pfxPassword = "") {
|
||||
const jksPassword = pfxPassword || "123456";
|
||||
try {
|
||||
|
@ -113,9 +135,7 @@ export class CertConverter {
|
|||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
await this.exec(
|
||||
`keytool -importkeystore -srckeystore ${p12Path} -srcstoretype PKCS12 -srcstorepass "${jksPassword}" -destkeystore ${jksPath} -deststoretype PKCS12 -deststorepass "${jksPassword}" `
|
||||
);
|
||||
await this.exec(`keytool -importkeystore -srckeystore ${p12Path} -srcstoretype PKCS12 -srcstorepass "${jksPassword}" -destkeystore ${jksPath} -deststoretype PKCS12 -deststorepass "${jksPassword}" `);
|
||||
fs.unlinkSync(p12Path);
|
||||
|
||||
const fileBuffer = fs.readFileSync(jksPath);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<a-form-item v-if="formState.yizhifu.enabled" label="易支付配置" :name="['yizhifu', 'accessId']" :required="true">
|
||||
<access-selector v-model="formState.yizhifu.accessId" type="yizhifu" from="sys" />
|
||||
<div class="helper">
|
||||
<a href="https://certd.docmirror.cn/comm/payments/yizhifu.html">彩虹易支付配置帮助文档</a>
|
||||
<a href="https://certd.docmirror.cn/guide/use/comm/payments/yizhifu.html">彩虹易支付配置帮助文档</a>
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
|||
</a-form-item>
|
||||
<a-form-item v-if="formState.alipay.enabled" label="支付宝配置" :name="['alipay', 'accessId']" :required="true">
|
||||
<access-selector v-model="formState.alipay.accessId" type="alipay" from="sys" />
|
||||
<div class="helper">需要开通电脑网站支付, <a href="https://certd.docmirror.cn/comm/payments/alipay.html">支付宝配置帮助文档</a></div>
|
||||
<div class="helper">需要开通电脑网站支付, <a href="https://certd.docmirror.cn/guide/use/comm/payments/alipay.html">支付宝配置帮助文档</a></div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="微信支付" :name="['wxpay', 'enabled']" :required="true">
|
||||
|
@ -25,7 +25,7 @@
|
|||
</a-form-item>
|
||||
<a-form-item v-if="formState.wxpay.enabled" label="微信支付配置" :name="['wxpay', 'accessId']" :required="true">
|
||||
<access-selector v-model="formState.wxpay.accessId" type="wxpay" from="sys" />
|
||||
<div class="helper">需要开通Native支付, <a href="https://certd.docmirror.cn/comm/payments/wxpay.html">微信配置帮助文档</a></div>
|
||||
<div class="helper">需要开通Native支付, <a href="https://certd.docmirror.cn/guide/use/comm/payments/wxpay.html">微信配置帮助文档</a></div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label=" " :colon="false" :wrapper-col="{ span: 16 }">
|
||||
|
|
|
@ -39,6 +39,7 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
|
|||
{ value: 'der', label: 'der,一般用于Apache' },
|
||||
{ value: 'jks', label: 'jks,一般用于JAVA应用' },
|
||||
{ value: 'one', label: '证书私钥一体,crt+key简单合并为一个pem文件' },
|
||||
{ value: 'p7b', label: 'p7b格式' },
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
|
@ -71,7 +72,7 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
|
|||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.certType === 'pem';
|
||||
return form.certType === 'pem' || form.certType === 'p7b' ;
|
||||
})
|
||||
}
|
||||
`,
|
||||
|
@ -169,6 +170,24 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
|
|||
})
|
||||
onePath!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: 'p7b证书保存路径',
|
||||
helper: '填写应用原本的证书保存路径,路径要包含证书文件名,例如:/tmp/domain_cert.p7b',
|
||||
component: {
|
||||
placeholder: '/root/deploy/app/domain_cert.p7b',
|
||||
},
|
||||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.certType === 'p7b';
|
||||
})
|
||||
}
|
||||
`,
|
||||
required: true,
|
||||
rules: [{ type: 'filepath' }],
|
||||
})
|
||||
p7bPath!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '主机登录配置',
|
||||
helper: 'access授权',
|
||||
|
@ -277,12 +296,17 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
|
|||
})
|
||||
hostOnePath!: string;
|
||||
|
||||
@TaskOutput({
|
||||
title: 'p7b证书保存路径',
|
||||
})
|
||||
hostP7bPath!: string;
|
||||
|
||||
async onInstance() {}
|
||||
|
||||
|
||||
async execute(): Promise<void> {
|
||||
const { cert, accessId } = this;
|
||||
let { crtPath, keyPath, icPath, pfxPath, derPath, jksPath, onePath } = this;
|
||||
let { crtPath, keyPath, icPath, pfxPath, derPath, jksPath, onePath,p7bPath } = this;
|
||||
const certReader = new CertReader(cert);
|
||||
|
||||
const executeCmd = async ( script:string)=> {
|
||||
|
@ -308,6 +332,7 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
|
|||
env['HOST_DER_PATH'] = this.hostDerPath || '';
|
||||
env['HOST_JKS_PATH'] = this.hostJksPath || '';
|
||||
env['HOST_ONE_PATH'] = this.hostOnePath || '';
|
||||
env['HOST_P7B_PATH'] = this.hostOnePath || '';
|
||||
}
|
||||
|
||||
const scripts = script.split('\n');
|
||||
|
@ -320,7 +345,7 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
|
|||
}
|
||||
|
||||
const handle = async (opts: CertReaderHandleContext) => {
|
||||
const { tmpCrtPath, tmpKeyPath, tmpDerPath, tmpJksPath, tmpPfxPath, tmpIcPath, tmpOnePath } = opts;
|
||||
const { tmpCrtPath, tmpKeyPath, tmpDerPath, tmpJksPath, tmpPfxPath, tmpIcPath, tmpOnePath ,tmpP7bPath} = opts;
|
||||
|
||||
if (accessId == null) {
|
||||
this.logger.error('复制到当前主机功能已迁移到 “复制到本机”插件,请换成复制到本机插件');
|
||||
|
@ -392,6 +417,14 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
|
|||
remotePath: this.onePath,
|
||||
});
|
||||
}
|
||||
if (this.p7bPath) {
|
||||
this.logger.info(`上传p7b证书到主机:${this.p7bPath}`);
|
||||
p7bPath = this.p7bPath.trim();
|
||||
transports.push({
|
||||
localPath: tmpP7bPath,
|
||||
remotePath: this.p7bPath,
|
||||
});
|
||||
}
|
||||
|
||||
this.logger.info('开始上传文件到服务器');
|
||||
await sshClient.uploadFiles({
|
||||
|
@ -410,6 +443,7 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
|
|||
this.hostDerPath = derPath;
|
||||
this.hostJksPath = jksPath;
|
||||
this.hostOnePath = onePath;
|
||||
this.hostP7bPath = p7bPath;
|
||||
};
|
||||
|
||||
//执行前置命令
|
||||
|
|
Loading…
Reference in New Issue