mirror of https://github.com/certd/certd
perf: http校验方式,支持七牛云oss、阿里云oss、腾讯云cos
parent
297d09c5ad
commit
3f74d4d9e5
|
@ -186,11 +186,12 @@ export class AcmeService {
|
||||||
const filePath = `.well-known/acme-challenge/${challenge.token}`;
|
const filePath = `.well-known/acme-challenge/${challenge.token}`;
|
||||||
const fileContents = keyAuthorization;
|
const fileContents = keyAuthorization;
|
||||||
this.logger.info(`校验 ${fullDomain} ,准备上传文件:${filePath}`);
|
this.logger.info(`校验 ${fullDomain} ,准备上传文件:${filePath}`);
|
||||||
await httpUploader.upload(filePath, fileContents);
|
await httpUploader.upload(filePath, Buffer.from(fileContents));
|
||||||
this.logger.info(`上传文件【${filePath}】成功`);
|
this.logger.info(`上传文件【${filePath}】成功`);
|
||||||
return {
|
return {
|
||||||
challenge,
|
challenge,
|
||||||
keyAuthorization,
|
keyAuthorization,
|
||||||
|
httpUploader,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -248,7 +249,8 @@ export class AcmeService {
|
||||||
const httpVerifyPlan = domainVerifyPlan.httpVerifyPlan;
|
const httpVerifyPlan = domainVerifyPlan.httpVerifyPlan;
|
||||||
if (httpVerifyPlan) {
|
if (httpVerifyPlan) {
|
||||||
const httpChallenge = getChallenge("http-01");
|
const httpChallenge = getChallenge("http-01");
|
||||||
return await doHttpVerify(httpChallenge, httpVerifyPlan[fullDomain].httpUploader);
|
const plan = httpVerifyPlan[fullDomain];
|
||||||
|
return await doHttpVerify(httpChallenge, plan.httpUploader);
|
||||||
} else {
|
} else {
|
||||||
throw new Error("未找到域名【" + fullDomain + "】的http校验配置");
|
throw new Error("未找到域名【" + fullDomain + "】的http校验配置");
|
||||||
}
|
}
|
||||||
|
|
|
@ -416,9 +416,14 @@ HTTP文件验证:不支持泛域名,需要配置网站文件上传`,
|
||||||
for (const key in domainVerifyPlan.httpVerifyPlan) {
|
for (const key in domainVerifyPlan.httpVerifyPlan) {
|
||||||
const httpRecord = domainVerifyPlan.httpVerifyPlan[key];
|
const httpRecord = domainVerifyPlan.httpVerifyPlan[key];
|
||||||
const access = await this.ctx.accessService.getById(httpRecord.httpUploaderAccess);
|
const access = await this.ctx.accessService.getById(httpRecord.httpUploaderAccess);
|
||||||
|
let rootDir = httpRecord.httpUploadRootDir;
|
||||||
|
if (!rootDir.endsWith("/") && !rootDir.endsWith("\\")) {
|
||||||
|
rootDir = rootDir + "/";
|
||||||
|
}
|
||||||
|
this.logger.info("上传方式", httpRecord.httpUploaderType);
|
||||||
const httpUploader = await httpChallengeUploaderFactory.createUploaderByType(httpRecord.httpUploaderType, {
|
const httpUploader = await httpChallengeUploaderFactory.createUploaderByType(httpRecord.httpUploaderType, {
|
||||||
access,
|
access,
|
||||||
rootDir: httpRecord.httpUploadRootDir,
|
rootDir: rootDir,
|
||||||
ctx: httpUploaderContext,
|
ctx: httpUploaderContext,
|
||||||
});
|
});
|
||||||
httpVerifyPlan[key] = {
|
httpVerifyPlan[key] = {
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { IAccessService } from "@certd/pipeline";
|
||||||
import { ILogger, utils } from "@certd/basic";
|
import { ILogger, utils } from "@certd/basic";
|
||||||
|
|
||||||
export type HttpChallengeUploader = {
|
export type HttpChallengeUploader = {
|
||||||
upload: (fileName: string, fileContent: string) => Promise<void>;
|
upload: (fileName: string, fileContent: Buffer) => Promise<void>;
|
||||||
remove: (fileName: string) => Promise<void>;
|
remove: (fileName: string) => Promise<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -31,5 +31,5 @@ export abstract class BaseHttpChallengeUploader<A> implements HttpChallengeUploa
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract remove(fileName: string): Promise<void>;
|
abstract remove(fileName: string): Promise<void>;
|
||||||
abstract upload(fileName: string, fileContent: string): Promise<void>;
|
abstract upload(fileName: string, fileContent: Buffer): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { AliossAccess, AliyunAccess } from "@certd/plugin-lib";
|
||||||
import { AliossClient } from "@certd/plugin-lib";
|
import { AliossClient } from "@certd/plugin-lib";
|
||||||
|
|
||||||
export class AliossHttpChallengeUploader extends BaseHttpChallengeUploader<AliossAccess> {
|
export class AliossHttpChallengeUploader extends BaseHttpChallengeUploader<AliossAccess> {
|
||||||
async upload(filePath: string, fileContent: string) {
|
async upload(filePath: string, fileContent: Buffer) {
|
||||||
const aliyunAccess = await this.ctx.accessService.getById<AliyunAccess>(this.access.accessId);
|
const aliyunAccess = await this.ctx.accessService.getById<AliyunAccess>(this.access.accessId);
|
||||||
const client = new AliossClient({
|
const client = new AliossClient({
|
||||||
access: aliyunAccess,
|
access: aliyunAccess,
|
||||||
|
@ -11,16 +11,19 @@ export class AliossHttpChallengeUploader extends BaseHttpChallengeUploader<Alios
|
||||||
region: this.access.region,
|
region: this.access.region,
|
||||||
});
|
});
|
||||||
|
|
||||||
await client.uploadFile(filePath, Buffer.from(fileContent));
|
const key = this.rootDir + filePath;
|
||||||
|
this.logger.info(`开始上传文件: ${key}`);
|
||||||
|
await client.uploadFile(key, fileContent);
|
||||||
|
|
||||||
this.logger.info(`校验文件上传成功: ${filePath}`);
|
this.logger.info(`校验文件上传成功: ${filePath}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async remove(filePath: string) {
|
async remove(filePath: string) {
|
||||||
|
const key = this.rootDir + filePath;
|
||||||
// remove file from alioss
|
// remove file from alioss
|
||||||
const client = await this.getAliossClient();
|
const client = await this.getAliossClient();
|
||||||
await client.removeFile(filePath);
|
await client.removeFile(key);
|
||||||
this.logger.info(`文件删除成功: ${filePath}`);
|
this.logger.info(`文件删除成功: ${key}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getAliossClient() {
|
private async getAliossClient() {
|
||||||
|
|
|
@ -1,24 +1,41 @@
|
||||||
import { BaseHttpChallengeUploader } from "../api.js";
|
import { BaseHttpChallengeUploader } from "../api.js";
|
||||||
import { FtpAccess, FtpClient } from "@certd/plugin-lib";
|
import { FtpAccess, FtpClient } from "@certd/plugin-lib";
|
||||||
|
import path from "path";
|
||||||
|
import os from "os";
|
||||||
|
import fs from "fs";
|
||||||
|
|
||||||
export class FtpHttpChallengeUploader extends BaseHttpChallengeUploader<FtpAccess> {
|
export class FtpHttpChallengeUploader extends BaseHttpChallengeUploader<FtpAccess> {
|
||||||
async upload(fileName: string, fileContent: string) {
|
async upload(filePath: string, fileContent: Buffer) {
|
||||||
const client = new FtpClient({
|
const client = new FtpClient({
|
||||||
access: this.access,
|
access: this.access,
|
||||||
logger: this.logger,
|
logger: this.logger,
|
||||||
});
|
});
|
||||||
await client.connect(async (client) => {
|
await client.connect(async (client) => {
|
||||||
await client.upload(fileName, fileContent);
|
const tmpFilePath = path.join(os.tmpdir(), "cert", "http", filePath);
|
||||||
|
const dir = path.dirname(tmpFilePath);
|
||||||
|
if (!fs.existsSync(dir)) {
|
||||||
|
fs.mkdirSync(dir, { recursive: true });
|
||||||
|
}
|
||||||
|
fs.writeFileSync(tmpFilePath, fileContent);
|
||||||
|
try {
|
||||||
|
// Write file to temp path
|
||||||
|
const path = this.rootDir + filePath;
|
||||||
|
await client.upload(path, tmpFilePath);
|
||||||
|
} finally {
|
||||||
|
// Remove temp file
|
||||||
|
fs.unlinkSync(tmpFilePath);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async remove(fileName: string) {
|
async remove(filePath: string) {
|
||||||
const client = new FtpClient({
|
const client = new FtpClient({
|
||||||
access: this.access,
|
access: this.access,
|
||||||
logger: this.logger,
|
logger: this.logger,
|
||||||
});
|
});
|
||||||
await client.connect(async (client) => {
|
await client.connect(async (client) => {
|
||||||
await client.client.remove(fileName);
|
const path = this.rootDir + filePath;
|
||||||
|
await client.client.remove(path);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,31 @@
|
||||||
import { BaseHttpChallengeUploader } from "../api.js";
|
import { BaseHttpChallengeUploader } from "../api.js";
|
||||||
import { QiniuOssAccess } from "@certd/plugin-lib/dist/qiniu/access-oss";
|
import { QiniuOssAccess, QiniuClient, QiniuAccess } from "@certd/plugin-lib";
|
||||||
|
|
||||||
export class QiniuOssHttpChallengeUploader extends BaseHttpChallengeUploader<QiniuOssAccess> {
|
export class QiniuOssHttpChallengeUploader extends BaseHttpChallengeUploader<QiniuOssAccess> {
|
||||||
async upload(fileName: string, fileContent: string) {
|
async upload(filePath: string, fileContent: Buffer) {
|
||||||
return null;
|
const qiniuAccess = await this.ctx.accessService.getById<QiniuAccess>(this.access.accessId);
|
||||||
|
const client = new QiniuClient({
|
||||||
|
access: qiniuAccess,
|
||||||
|
logger: this.logger,
|
||||||
|
http: this.ctx.utils.http,
|
||||||
|
});
|
||||||
|
if (this.rootDir.endsWith("/")) {
|
||||||
|
this.rootDir = this.rootDir.slice(0, -1);
|
||||||
|
}
|
||||||
|
await client.uploadFile(this.access.bucket, this.rootDir + filePath, fileContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
async remove(fileName: string) {}
|
async remove(filePath: string) {
|
||||||
|
const qiniuAccess = await this.ctx.accessService.getById<QiniuAccess>(this.access.accessId);
|
||||||
|
const client = new QiniuClient({
|
||||||
|
access: qiniuAccess,
|
||||||
|
logger: this.logger,
|
||||||
|
http: this.ctx.utils.http,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.rootDir.endsWith("/")) {
|
||||||
|
this.rootDir = this.rootDir.slice(0, -1);
|
||||||
|
}
|
||||||
|
await client.removeFile(this.access.bucket, this.rootDir + filePath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,17 @@ import os from "os";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
|
|
||||||
export class SshHttpChallengeUploader extends BaseHttpChallengeUploader<SshAccess> {
|
export class SshHttpChallengeUploader extends BaseHttpChallengeUploader<SshAccess> {
|
||||||
async upload(fileName: string, fileContent: string) {
|
async upload(filePath: string, fileContent: Buffer) {
|
||||||
const tmpFilePath = path.join(os.tmpdir(), "cert", "http", fileName);
|
const tmpFilePath = path.join(os.tmpdir(), "cert", "http", filePath);
|
||||||
|
|
||||||
// Write file to temp path
|
// Write file to temp path
|
||||||
|
const dir = path.dirname(tmpFilePath);
|
||||||
|
if (!fs.existsSync(dir)) {
|
||||||
|
fs.mkdirSync(dir, { recursive: true });
|
||||||
|
}
|
||||||
fs.writeFileSync(tmpFilePath, fileContent);
|
fs.writeFileSync(tmpFilePath, fileContent);
|
||||||
|
|
||||||
|
const key = this.rootDir + filePath;
|
||||||
try {
|
try {
|
||||||
const client = new SshClient(this.logger);
|
const client = new SshClient(this.logger);
|
||||||
await client.uploadFiles({
|
await client.uploadFiles({
|
||||||
|
@ -17,8 +23,8 @@ export class SshHttpChallengeUploader extends BaseHttpChallengeUploader<SshAcces
|
||||||
mkdirs: true,
|
mkdirs: true,
|
||||||
transports: [
|
transports: [
|
||||||
{
|
{
|
||||||
localPath: fileName,
|
localPath: tmpFilePath,
|
||||||
remotePath: fileName,
|
remotePath: key,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
@ -30,9 +36,10 @@ export class SshHttpChallengeUploader extends BaseHttpChallengeUploader<SshAcces
|
||||||
|
|
||||||
async remove(filePath: string) {
|
async remove(filePath: string) {
|
||||||
const client = new SshClient(this.logger);
|
const client = new SshClient(this.logger);
|
||||||
|
const key = this.rootDir + filePath;
|
||||||
await client.removeFiles({
|
await client.removeFiles({
|
||||||
connectConf: this.access,
|
connectConf: this.access,
|
||||||
files: [filePath],
|
files: [key],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,28 @@
|
||||||
import { BaseHttpChallengeUploader } from "../api.js";
|
import { BaseHttpChallengeUploader } from "../api.js";
|
||||||
import { TencentCosAccess } from "@certd/plugin-lib/dist/tencent/access-cos";
|
import { TencentAccess, TencentCosAccess, TencentCosClient } from "@certd/plugin-lib";
|
||||||
|
|
||||||
export class TencentCosHttpChallengeUploader extends BaseHttpChallengeUploader<TencentCosAccess> {
|
export class TencentCosHttpChallengeUploader extends BaseHttpChallengeUploader<TencentCosAccess> {
|
||||||
async upload(fileName: string, fileContent: string) {
|
async upload(filePath: string, fileContent: Buffer) {
|
||||||
return null;
|
const access = await this.ctx.accessService.getById<TencentAccess>(this.access.accessId);
|
||||||
|
const client = new TencentCosClient({
|
||||||
|
access: access,
|
||||||
|
logger: this.logger,
|
||||||
|
region: this.access.region,
|
||||||
|
bucket: this.access.bucket,
|
||||||
|
});
|
||||||
|
const key = this.rootDir + filePath;
|
||||||
|
await client.uploadFile(key, fileContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
async remove(fileName: string) {}
|
async remove(filePath: string) {
|
||||||
|
const access = await this.ctx.accessService.getById<TencentAccess>(this.access.accessId);
|
||||||
|
const client = new TencentCosClient({
|
||||||
|
access: access,
|
||||||
|
logger: this.logger,
|
||||||
|
region: this.access.region,
|
||||||
|
bucket: this.access.bucket,
|
||||||
|
});
|
||||||
|
const key = this.rootDir + filePath;
|
||||||
|
await client.removeFile(key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,14 +21,17 @@
|
||||||
"@kubernetes/client-node": "0.21.0",
|
"@kubernetes/client-node": "0.21.0",
|
||||||
"ali-oss": "^6.21.0",
|
"ali-oss": "^6.21.0",
|
||||||
"basic-ftp": "^5.0.5",
|
"basic-ftp": "^5.0.5",
|
||||||
|
"cos-nodejs-sdk-v5": "^2.14.6",
|
||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.7",
|
||||||
"iconv-lite": "^0.6.3",
|
"iconv-lite": "^0.6.3",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
|
"qiniu": "^7.12.0",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^5.0.5",
|
||||||
"socks": "^2.8.3",
|
"socks": "^2.8.3",
|
||||||
"socks-proxy-agent": "^8.0.4",
|
"socks-proxy-agent": "^8.0.4",
|
||||||
"ssh2": "^1.15.0",
|
"ssh2": "^1.15.0",
|
||||||
"strip-ansi": "^7.1.0"
|
"strip-ansi": "^7.1.0",
|
||||||
|
"tencentcloud-sdk-nodejs": "^4.0.1005"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/chai": "^4.3.3",
|
"@types/chai": "^4.3.3",
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
export * from "./access.js";
|
export * from "./access.js";
|
||||||
|
export * from "./access-oss.js";
|
||||||
|
export * from "./lib/sdk.js";
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
import { HttpClient, ILogger } from "@certd/basic";
|
||||||
|
import { QiniuAccess } from "../access.js";
|
||||||
|
|
||||||
|
export type QiniuCertInfo = {
|
||||||
|
key: string;
|
||||||
|
crt: string;
|
||||||
|
};
|
||||||
|
export class QiniuClient {
|
||||||
|
http: HttpClient;
|
||||||
|
access: QiniuAccess;
|
||||||
|
logger: ILogger;
|
||||||
|
constructor(opts: { http: HttpClient; access: QiniuAccess; logger: ILogger }) {
|
||||||
|
this.http = opts.http;
|
||||||
|
this.access = opts.access;
|
||||||
|
this.logger = opts.logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
async uploadCert(cert: QiniuCertInfo, certName?: string) {
|
||||||
|
const url = "https://api.qiniu.com/sslcert";
|
||||||
|
|
||||||
|
const body = {
|
||||||
|
name: certName,
|
||||||
|
common_name: "certd",
|
||||||
|
pri: cert.key,
|
||||||
|
ca: cert.crt,
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await this.doRequest(url, "post", body);
|
||||||
|
|
||||||
|
return res.certID;
|
||||||
|
}
|
||||||
|
|
||||||
|
async bindCert(body: { certid: string; domain: string }) {
|
||||||
|
const url = "https://api.qiniu.com/cert/bind";
|
||||||
|
return await this.doRequest(url, "post", body);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getCertBindings() {
|
||||||
|
const url = "https://api.qiniu.com/cert/bindings";
|
||||||
|
const res = await this.doRequest(url, "get");
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
async doRequest(url: string, method: string, body?: any) {
|
||||||
|
const { generateAccessToken } = await import("qiniu/qiniu/util.js");
|
||||||
|
const token = generateAccessToken(this.access, url);
|
||||||
|
const res = await this.http.request({
|
||||||
|
url,
|
||||||
|
method: method,
|
||||||
|
headers: {
|
||||||
|
Authorization: token,
|
||||||
|
},
|
||||||
|
data: body,
|
||||||
|
logRes: false,
|
||||||
|
});
|
||||||
|
if (res && res.error) {
|
||||||
|
if (res.error.includes("domaintype")) {
|
||||||
|
throw new Error("请求失败:" + res.error + ",该域名属于CDN域名,请使用部署到七牛云CDN插件");
|
||||||
|
}
|
||||||
|
throw new Error("请求失败:" + res.error);
|
||||||
|
}
|
||||||
|
console.log("res", res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
async doRequestV2(opts: { url: string; method: string; body?: any; contentType: string }) {
|
||||||
|
const { HttpClient } = await import("qiniu/qiniu/httpc/client.js");
|
||||||
|
const { QiniuAuthMiddleware } = await import("qiniu/qiniu/httpc/middleware/qiniuAuth.js");
|
||||||
|
// X-Qiniu-Date: 20060102T150405Z
|
||||||
|
const auth = new QiniuAuthMiddleware({
|
||||||
|
mac: {
|
||||||
|
...this.access,
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const http = new HttpClient({ timeout: 10000, middlewares: [auth] });
|
||||||
|
console.log("http", http);
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
http.get({
|
||||||
|
url: opts.url,
|
||||||
|
headers: {
|
||||||
|
"Content-Type": opts.contentType,
|
||||||
|
},
|
||||||
|
callback: (nullable, res) => {
|
||||||
|
console.log("nullable", nullable, "res", res);
|
||||||
|
if (res?.error) {
|
||||||
|
reject(res);
|
||||||
|
} else {
|
||||||
|
resolve(res);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async uploadFile(bucket: string, key: string, content: Buffer) {
|
||||||
|
const sdk = await import("qiniu");
|
||||||
|
const qiniu = sdk.default;
|
||||||
|
const mac = new qiniu.auth.digest.Mac(this.access.accessKey, this.access.secretKey);
|
||||||
|
const options = {
|
||||||
|
scope: bucket,
|
||||||
|
};
|
||||||
|
const putPolicy = new qiniu.rs.PutPolicy(options);
|
||||||
|
const uploadToken = putPolicy.uploadToken(mac);
|
||||||
|
|
||||||
|
const config = new qiniu.conf.Config();
|
||||||
|
const formUploader = new qiniu.form_up.FormUploader(config);
|
||||||
|
const putExtra = new qiniu.form_up.PutExtra();
|
||||||
|
// 文件上传
|
||||||
|
const { data, resp } = await formUploader.put(uploadToken, key, content, putExtra);
|
||||||
|
if (resp.statusCode === 200) {
|
||||||
|
this.logger.info("文件上传成功:" + key);
|
||||||
|
return data;
|
||||||
|
} else {
|
||||||
|
console.log(resp.statusCode);
|
||||||
|
throw new Error("上传失败:" + JSON.stringify(resp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async removeFile(bucket: string, key: string) {
|
||||||
|
const sdk = await import("qiniu");
|
||||||
|
const qiniu = sdk.default;
|
||||||
|
const mac = new qiniu.auth.digest.Mac(this.access.accessKey, this.access.secretKey);
|
||||||
|
const config = new qiniu.conf.Config();
|
||||||
|
config.useHttpsDomain = true;
|
||||||
|
const bucketManager = new qiniu.rs.BucketManager(mac, config);
|
||||||
|
|
||||||
|
const { resp } = await bucketManager.delete(bucket, key);
|
||||||
|
|
||||||
|
if (resp.statusCode === 200) {
|
||||||
|
this.logger.info("文件删除成功:" + key);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
throw new Error("删除失败:" + JSON.stringify(resp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -61,3 +61,5 @@ export class TencentCosAccess extends BaseAccess {
|
||||||
})
|
})
|
||||||
bucket = "";
|
bucket = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new TencentCosAccess();
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
export * from "./access.js";
|
export * from "./access.js";
|
||||||
|
export * from "./access-cos.js";
|
||||||
|
export * from "./lib/index.js";
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
import { TencentAccess } from "../access.js";
|
||||||
|
import { ILogger } from "@certd/basic";
|
||||||
|
|
||||||
|
export class TencentCosClient {
|
||||||
|
access: TencentAccess;
|
||||||
|
logger: ILogger;
|
||||||
|
region: string;
|
||||||
|
bucket: string;
|
||||||
|
|
||||||
|
constructor(opts: { access: TencentAccess; logger: ILogger; region: string; bucket: string }) {
|
||||||
|
this.access = opts.access;
|
||||||
|
this.logger = opts.logger;
|
||||||
|
this.bucket = opts.bucket;
|
||||||
|
this.region = opts.region;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getCosClient() {
|
||||||
|
const sdk = await import("cos-nodejs-sdk-v5");
|
||||||
|
const clientConfig = {
|
||||||
|
SecretId: this.access.secretId,
|
||||||
|
SecretKey: this.access.secretKey,
|
||||||
|
};
|
||||||
|
return new sdk.default(clientConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
async uploadFile(key: string, file: Buffer) {
|
||||||
|
const cos = await this.getCosClient();
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
cos.putObject(
|
||||||
|
{
|
||||||
|
Bucket: this.bucket /* 必须 */,
|
||||||
|
Region: this.region /* 必须 */,
|
||||||
|
Key: key /* 必须 */,
|
||||||
|
Body: file, // 上传文件对象
|
||||||
|
onProgress: function (progressData) {
|
||||||
|
console.log(JSON.stringify(progressData));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
function (err, data) {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resolve(data);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async removeFile(key: string) {
|
||||||
|
const cos = await this.getCosClient();
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
cos.deleteObject(
|
||||||
|
{
|
||||||
|
Bucket: this.bucket,
|
||||||
|
Region: this.region,
|
||||||
|
Key: key,
|
||||||
|
},
|
||||||
|
function (err, data) {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resolve(data);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
export * from "./ssl-client.js";
|
||||||
|
export * from "./cos-client.js";
|
|
@ -1,6 +1,10 @@
|
||||||
import { TencentAccess } from '@certd/plugin-lib';
|
import { ILogger } from "@certd/basic";
|
||||||
import { CertInfo } from '@certd/plugin-cert';
|
import { TencentAccess } from "../access.js";
|
||||||
import { ILogger } from '@certd/basic';
|
|
||||||
|
export type TencentCertInfo = {
|
||||||
|
key: string;
|
||||||
|
crt: string;
|
||||||
|
};
|
||||||
export class TencentSslClient {
|
export class TencentSslClient {
|
||||||
access: TencentAccess;
|
access: TencentAccess;
|
||||||
logger: ILogger;
|
logger: ILogger;
|
||||||
|
@ -11,7 +15,7 @@ export class TencentSslClient {
|
||||||
this.region = opts.region;
|
this.region = opts.region;
|
||||||
}
|
}
|
||||||
async getSslClient(): Promise<any> {
|
async getSslClient(): Promise<any> {
|
||||||
const sdk = await import('tencentcloud-sdk-nodejs/tencentcloud/services/ssl/v20191205/index.js');
|
const sdk = await import("tencentcloud-sdk-nodejs/tencentcloud/services/ssl/v20191205/index.js");
|
||||||
const SslClient = sdk.v20191205.Client;
|
const SslClient = sdk.v20191205.Client;
|
||||||
|
|
||||||
const clientConfig = {
|
const clientConfig = {
|
||||||
|
@ -22,7 +26,7 @@ export class TencentSslClient {
|
||||||
region: this.region,
|
region: this.region,
|
||||||
profile: {
|
profile: {
|
||||||
httpProfile: {
|
httpProfile: {
|
||||||
endpoint: 'ssl.tencentcloudapi.com',
|
endpoint: "ssl.tencentcloudapi.com",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -32,11 +36,11 @@ export class TencentSslClient {
|
||||||
|
|
||||||
checkRet(ret: any) {
|
checkRet(ret: any) {
|
||||||
if (!ret || ret.Error) {
|
if (!ret || ret.Error) {
|
||||||
throw new Error('请求失败:' + ret.Error.Code + ',' + ret.Error.Message);
|
throw new Error("请求失败:" + ret.Error.Code + "," + ret.Error.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async uploadToTencent(opts: { certName: string; cert: CertInfo }): Promise<string> {
|
async uploadToTencent(opts: { certName: string; cert: TencentCertInfo }): Promise<string> {
|
||||||
const client = await this.getSslClient();
|
const client = await this.getSslClient();
|
||||||
const params = {
|
const params = {
|
||||||
CertificatePublicKey: opts.cert.crt,
|
CertificatePublicKey: opts.cert.crt,
|
||||||
|
@ -45,7 +49,7 @@ export class TencentSslClient {
|
||||||
};
|
};
|
||||||
const ret = await client.UploadCertificate(params);
|
const ret = await client.UploadCertificate(params);
|
||||||
this.checkRet(ret);
|
this.checkRet(ret);
|
||||||
this.logger.info('证书上传成功:tencentCertId=', ret.CertificateId);
|
this.logger.info("证书上传成功:tencentCertId=", ret.CertificateId);
|
||||||
return ret.CertificateId;
|
return ret.CertificateId;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ watch(
|
||||||
},
|
},
|
||||||
(value: any) => {
|
(value: any) => {
|
||||||
if (value) {
|
if (value) {
|
||||||
|
debugger;
|
||||||
records.value = {
|
records.value = {
|
||||||
...value
|
...value
|
||||||
};
|
};
|
||||||
|
|
|
@ -138,18 +138,7 @@ function showError(error: string) {
|
||||||
|
|
||||||
type DomainGroup = Record<string, Record<string, CnameRecord>>;
|
type DomainGroup = Record<string, Record<string, CnameRecord>>;
|
||||||
|
|
||||||
watch(
|
|
||||||
() => {
|
|
||||||
return props.defaultType;
|
|
||||||
},
|
|
||||||
(value: string) => {
|
|
||||||
planRef.value = {};
|
|
||||||
onDomainsChanged(props.domains);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
function onDomainsChanged(domains: string[]) {
|
function onDomainsChanged(domains: string[]) {
|
||||||
console.log("域名变化", domains);
|
|
||||||
if (domains == null) {
|
if (domains == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -183,22 +172,46 @@ function onDomainsChanged(domains: string[]) {
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
type: props.defaultType || "cname",
|
type: props.defaultType || "cname",
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
cnameVerifyPlan: {
|
cnameVerifyPlan: {},
|
||||||
...subDomains
|
|
||||||
},
|
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
httpVerifyPlan: {
|
httpVerifyPlan: {}
|
||||||
...subDomains
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
planRef.value[domain] = planItem;
|
planRef.value[domain] = planItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cnameOrigin = planItem.cnameVerifyPlan;
|
||||||
|
const httpOrigin = planItem.httpVerifyPlan;
|
||||||
|
planItem.cnameVerifyPlan = {};
|
||||||
|
planItem.httpVerifyPlan = {};
|
||||||
|
for (const subDomain in subDomains) {
|
||||||
|
if (!cnameOrigin[subDomain]) {
|
||||||
|
//@ts-ignore
|
||||||
|
planItem.cnameVerifyPlan[subDomain] = {
|
||||||
|
id: 0
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
planItem.cnameVerifyPlan[subDomain] = cnameOrigin[subDomain];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const subDomain in subDomains) {
|
||||||
|
if (!httpOrigin[subDomain]) {
|
||||||
|
//@ts-ignore
|
||||||
|
planItem.httpVerifyPlan[subDomain] = {
|
||||||
|
domain: subDomain
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
planItem.httpVerifyPlan[subDomain] = httpOrigin[subDomain];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const cnamePlan = planItem.cnameVerifyPlan;
|
const cnamePlan = planItem.cnameVerifyPlan;
|
||||||
for (const subDomain in subDomains) {
|
for (const subDomain in subDomains) {
|
||||||
//@ts-ignore
|
if (!cnamePlan[subDomain]) {
|
||||||
cnamePlan[subDomain] = {
|
//@ts-ignore
|
||||||
id: 0
|
cnamePlan[subDomain] = {
|
||||||
};
|
id: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (const subDomain of Object.keys(cnamePlan)) {
|
for (const subDomain of Object.keys(cnamePlan)) {
|
||||||
if (!subDomains[subDomain]) {
|
if (!subDomains[subDomain]) {
|
||||||
|
@ -209,10 +222,13 @@ function onDomainsChanged(domains: string[]) {
|
||||||
// httpVerifyPlan
|
// httpVerifyPlan
|
||||||
const httpPlan = planItem.httpVerifyPlan;
|
const httpPlan = planItem.httpVerifyPlan;
|
||||||
for (const subDomain in subDomains) {
|
for (const subDomain in subDomains) {
|
||||||
//@ts-ignore
|
debugger;
|
||||||
httpPlan[subDomain] = {
|
if (!httpPlan[subDomain]) {
|
||||||
domain: subDomain
|
//@ts-ignore
|
||||||
};
|
httpPlan[subDomain] = {
|
||||||
|
domain: subDomain
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (const subDomain of Object.keys(httpPlan)) {
|
for (const subDomain of Object.keys(httpPlan)) {
|
||||||
if (!subDomains[subDomain]) {
|
if (!subDomains[subDomain]) {
|
||||||
|
@ -226,14 +242,15 @@ function onDomainsChanged(domains: string[]) {
|
||||||
delete planRef.value[domain];
|
delete planRef.value[domain];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
debugger;
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => {
|
() => {
|
||||||
return props.domains;
|
return props.domains && props.defaultType;
|
||||||
},
|
},
|
||||||
(domains: string[]) => {
|
() => {
|
||||||
onDomainsChanged(domains);
|
onDomainsChanged(props.domains);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
immediate: true,
|
immediate: true,
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||||
import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine, QiniuAccess } from '@certd/plugin-lib';
|
import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine, QiniuAccess, QiniuClient } from '@certd/plugin-lib';
|
||||||
import { CertInfo } from '@certd/plugin-cert';
|
import { CertInfo } from '@certd/plugin-cert';
|
||||||
import { optionsUtils } from '@certd/basic/dist/utils/util.options.js';
|
import { optionsUtils } from '@certd/basic/dist/utils/util.options.js';
|
||||||
import { QiniuClient } from '@certd/plugin-plus';
|
|
||||||
|
|
||||||
@IsTaskPlugin({
|
@IsTaskPlugin({
|
||||||
name: 'QiniuDeployCertToCDN',
|
name: 'QiniuDeployCertToCDN',
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskOutput } from '@certd/pipeline';
|
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskOutput } from '@certd/pipeline';
|
||||||
import { QiniuClient } from '@certd/plugin-plus';
|
|
||||||
import { CertInfo } from '@certd/plugin-cert';
|
import { CertInfo } from '@certd/plugin-cert';
|
||||||
import { QiniuAccess } from '@certd/plugin-lib';
|
import { QiniuAccess, QiniuClient } from '@certd/plugin-lib';
|
||||||
|
|
||||||
@IsTaskPlugin({
|
@IsTaskPlugin({
|
||||||
name: 'QiniuCertUpload',
|
name: 'QiniuCertUpload',
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||||
import { AbstractPlusTaskPlugin } from '@certd/plugin-plus';
|
import { AbstractPlusTaskPlugin } from '@certd/plugin-plus';
|
||||||
import { TencentSslClient } from '../../lib/index.js';
|
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { remove } from 'lodash-es';
|
import { remove } from 'lodash-es';
|
||||||
import { TencentAccess } from '@certd/plugin-lib';
|
import { TencentAccess, TencentSslClient } from '@certd/plugin-lib';
|
||||||
|
|
||||||
@IsTaskPlugin({
|
@IsTaskPlugin({
|
||||||
name: 'TencentDeleteExpiringCert',
|
name: 'TencentDeleteExpiringCert',
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||||
import { CertInfo } from '@certd/plugin-cert';
|
import { CertInfo } from '@certd/plugin-cert';
|
||||||
import { TencentSslClient } from '../../lib/index.js';
|
|
||||||
import { createRemoteSelectInputDefine } from '@certd/plugin-lib';
|
import { createRemoteSelectInputDefine } from '@certd/plugin-lib';
|
||||||
import { TencentAccess } from '@certd/plugin-lib';
|
import { TencentAccess, TencentSslClient } from '@certd/plugin-lib';
|
||||||
@IsTaskPlugin({
|
@IsTaskPlugin({
|
||||||
name: 'TencentDeployCertToCDNv2',
|
name: 'TencentDeployCertToCDNv2',
|
||||||
title: '腾讯云-部署到CDN-v2',
|
title: '腾讯云-部署到CDN-v2',
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||||
import { CertInfo } from '@certd/plugin-cert';
|
import { CertInfo } from '@certd/plugin-cert';
|
||||||
import { createRemoteSelectInputDefine } from '@certd/plugin-lib';
|
import { createRemoteSelectInputDefine, TencentSslClient } from '@certd/plugin-lib';
|
||||||
import { TencentSslClient } from '../../lib/index.js';
|
|
||||||
|
|
||||||
@IsTaskPlugin({
|
@IsTaskPlugin({
|
||||||
name: 'DeployCertToTencentCosPlugin',
|
name: 'DeployCertToTencentCosPlugin',
|
||||||
|
|
Loading…
Reference in New Issue