perf: 部署到IIS插件

This commit is contained in:
xiaojunnuo
2024-11-30 17:36:47 +08:00
parent aedc462135
commit 1534f45236
10 changed files with 121 additions and 64 deletions
@@ -4,7 +4,6 @@ import type { CertInfo } from "./acme.js";
import { CertReader } from "./cert-reader.js";
import JSZip from "jszip";
import { CertConverter } from "./convert.js";
import fs from "fs";
import { pick } from "lodash-es";
export { CertReader };
@@ -59,6 +58,19 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
})
pfxPassword!: string;
@TaskInput({
title: "PFX证书转换参数",
value: "-macalg SHA1 -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES",
component: {
name: "a-input",
vModel: "value",
},
required: false,
order: 100,
helper: "兼容Server 2016,如果导入证书失败,请删除此参数",
})
pfxArgs = "-macalg SHA1 -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES";
@TaskInput({
title: "更新天数",
value: 35,
@@ -143,23 +155,18 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
const res = await converter.convert({
cert,
pfxPassword: this.pfxPassword,
pfxArgs: this.pfxArgs,
});
if (cert.pfx == null && res.pfxPath) {
const pfxBuffer = fs.readFileSync(res.pfxPath);
cert.pfx = pfxBuffer.toString("base64");
fs.unlinkSync(res.pfxPath);
if (cert.pfx == null && res.pfx) {
cert.pfx = res.pfx;
}
if (cert.der == null && res.derPath) {
const derBuffer = fs.readFileSync(res.derPath);
cert.der = derBuffer.toString("base64");
fs.unlinkSync(res.derPath);
if (cert.der == null && res.der) {
cert.der = res.der;
}
if (cert.jks == null && res.jksPath) {
const jksBuffer = fs.readFileSync(res.jksPath);
cert.jks = jksBuffer.toString("base64");
fs.unlinkSync(res.jksPath);
if (cert.jks == null && res.jks) {
cert.jks = res.jks;
}
this.logger.info("转换证书格式成功");
@@ -14,31 +14,31 @@ export class CertConverter {
constructor(opts: { logger: ILogger }) {
this.logger = opts.logger;
}
async convert(opts: { cert: CertInfo; pfxPassword: string }): Promise<{
pfxPath: string;
derPath: string;
jksPath: string;
async convert(opts: { cert: CertInfo; pfxPassword: string; pfxArgs: string }): Promise<{
pfx: string;
der: string;
jks: string;
}> {
const certReader = new CertReader(opts.cert);
let pfxPath: string;
let derPath: string;
let jksPath: string;
let pfx: string;
let der: string;
let jks: string;
const handle = async (ctx: CertReaderHandleContext) => {
// 调用openssl 转pfx
pfxPath = await this.convertPfx(ctx, opts.pfxPassword);
pfx = await this.convertPfx(ctx, opts.pfxPassword, opts.pfxArgs);
// 转der
derPath = await this.convertDer(ctx);
der = await this.convertDer(ctx);
jksPath = await this.convertJks(ctx, opts.pfxPassword);
jks = await this.convertJks(ctx, opts.pfxPassword);
};
await certReader.readCertFile({ logger: this.logger, handle });
return {
pfxPath,
derPath,
jksPath,
pfx,
der,
jks,
};
}
@@ -50,7 +50,7 @@ export class CertConverter {
});
}
private async convertPfx(opts: CertReaderHandleContext, pfxPassword: string) {
private async convertPfx(opts: CertReaderHandleContext, pfxPassword: string, pfxArgs: string) {
const { tmpCrtPath, tmpKeyPath } = opts;
const pfxPath = path.join(os.tmpdir(), "/certd/tmp/", Math.floor(Math.random() * 1000000) + "_cert.pfx");
@@ -65,12 +65,14 @@ export class CertConverter {
passwordArg = `-password pass:${pfxPassword}`;
}
// 兼容server 2016,旧版本不能用sha256
const oldPfxCmd = `openssl pkcs12 -macalg SHA1 -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -export -out ${pfxPath} -inkey ${tmpKeyPath} -in ${tmpCrtPath} ${passwordArg}`;
const oldPfxCmd = `openssl pkcs12 ${pfxArgs} -export -out ${pfxPath} -inkey ${tmpKeyPath} -in ${tmpCrtPath} ${passwordArg}`;
// const newPfx = `openssl pkcs12 -export -out ${pfxPath} -inkey ${tmpKeyPath} -in ${tmpCrtPath} ${passwordArg}`;
await this.exec(oldPfxCmd);
return pfxPath;
// const fileBuffer = fs.readFileSync(pfxPath);
// this.pfxCert = fileBuffer.toString("base64");
const fileBuffer = fs.readFileSync(pfxPath);
const pfxCert = fileBuffer.toString("base64");
fs.unlinkSync(pfxPath);
return pfxCert;
//
// const applyTime = new Date().getTime();
// const filename = reader.buildCertFileName("pfx", applyTime);
@@ -87,15 +89,10 @@ export class CertConverter {
}
await this.exec(`openssl x509 -outform der -in ${tmpCrtPath} -out ${derPath}`);
return derPath;
// const fileBuffer = fs.readFileSync(derPath);
// this.derCert = fileBuffer.toString("base64");
//
// const applyTime = new Date().getTime();
// const filename = reader.buildCertFileName("der", applyTime);
// this.saveFile(filename, fileBuffer);
const fileBuffer = fs.readFileSync(derPath);
const derCert = fileBuffer.toString("base64");
fs.unlinkSync(derPath);
return derCert;
}
async convertJks(opts: CertReaderHandleContext, pfxPassword = "") {
@@ -120,7 +117,11 @@ export class CertConverter {
`keytool -importkeystore -srckeystore ${p12Path} -srcstoretype PKCS12 -srcstorepass "${jksPassword}" -destkeystore ${jksPath} -deststoretype PKCS12 -deststorepass "${jksPassword}" `
);
fs.unlinkSync(p12Path);
return jksPath;
const fileBuffer = fs.readFileSync(jksPath);
const certBase64 = fileBuffer.toString("base64");
fs.unlinkSync(jksPath);
return certBase64;
} catch (e) {
this.logger.error("转换jks失败", e);
return;
+28 -14
View File
@@ -25,7 +25,7 @@ export class AsyncSsh2Client {
if (this.encoding) {
return iconv.decode(buffer, this.encoding);
}
return buffer.toString();
return buffer.toString().replaceAll("\r\n", "\n");
}
async connect() {
@@ -95,7 +95,12 @@ export class AsyncSsh2Client {
});
}
async exec(script: string) {
async exec(
script: string,
opts: {
throwOnStdErr?: boolean;
} = {}
): Promise<string> {
if (!script) {
this.logger.info("script 为空,取消执行");
return;
@@ -114,9 +119,17 @@ export class AsyncSsh2Client {
return;
}
let data = "";
let hasErrorLog = false;
stream
.on("close", (code: any, signal: any) => {
this.logger.info(`[${this.connConf.host}][close]:code:${code}`);
if (opts.throwOnStdErr == null && this.windows) {
opts.throwOnStdErr = true;
}
if (opts.throwOnStdErr && hasErrorLog) {
reject(new Error(data));
}
if (code === 0) {
resolve(data);
} else {
@@ -135,13 +148,14 @@ export class AsyncSsh2Client {
.stderr.on("data", (ret: Buffer) => {
const err = this.convert(iconv, ret);
data += err;
this.logger.info(`[${this.connConf.host}][error]: ` + err.trimEnd());
hasErrorLog = true;
this.logger.error(`[${this.connConf.host}][error]: ` + err.trimEnd());
});
});
});
}
async shell(script: string | string[]): Promise<string[]> {
async shell(script: string | string[]): Promise<string> {
return new Promise<any>((resolve, reject) => {
this.logger.info(`执行shell脚本:[${this.connConf.host}][shell]: ` + script);
this.conn.shell((err: Error, stream: any) => {
@@ -149,11 +163,11 @@ export class AsyncSsh2Client {
reject(err);
return;
}
const output: string[] = [];
let output = "";
function ansiHandle(data: string) {
data = data.replace(/\[[0-9]+;1H/g, "\n");
data = data.replace(/\[[0-9]+;1H/g, "");
data = stripAnsi(data);
return data;
return data.replaceAll("\r\n", "\n");
}
stream
.on("close", (code: any) => {
@@ -163,7 +177,7 @@ export class AsyncSsh2Client {
.on("data", (ret: Buffer) => {
const data = ansiHandle(ret.toString());
this.logger.info(data);
output.push(data);
output += data;
})
.on("error", (err: any) => {
reject(err);
@@ -171,8 +185,8 @@ export class AsyncSsh2Client {
})
.stderr.on("data", (ret: Buffer) => {
const data = ansiHandle(ret.toString());
output.push(data);
this.logger.info(`[${this.connConf.host}][error]: ` + data);
output += data;
this.logger.error(`[${this.connConf.host}][error]: ` + data);
});
//保证windows下正常退出
const exit = "\r\nexit\r\n";
@@ -269,7 +283,7 @@ export class SshClient {
async getIsCmd(options: { connectConf: SshAccess }) {
const { connectConf } = options;
return await this._call({
return await this._call<boolean>({
connectConf,
callable: async (conn: AsyncSsh2Client) => {
return await this.isCmd(conn);
@@ -285,7 +299,7 @@ export class SshClient {
* Set-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\cmd.exe"
* @param options
*/
async exec(options: { connectConf: SshAccess; script: string | Array<string>; env?: any }): Promise<string[]> {
async exec(options: { connectConf: SshAccess; script: string | Array<string>; env?: any }): Promise<string> {
let { script } = options;
const { connectConf } = options;
@@ -337,7 +351,7 @@ export class SshClient {
});
}
async shell(options: { connectConf: SshAccess; script: string | Array<string> }): Promise<string[]> {
async shell(options: { connectConf: SshAccess; script: string | Array<string> }): Promise<string> {
let { script } = options;
const { connectConf } = options;
if (_.isArray(script)) {
@@ -361,7 +375,7 @@ export class SshClient {
});
}
async _call(options: { connectConf: SshAccess; callable: any }): Promise<string[]> {
async _call<T = any>(options: { connectConf: SshAccess; callable: (conn: AsyncSsh2Client) => Promise<T> }): Promise<T> {
const { connectConf, callable } = options;
const conn = new AsyncSsh2Client(connectConf, this.logger);
try {