mirror of
https://github.com/certd/certd.git
synced 2026-05-16 21:27:34 +08:00
Merge branch 'v2-dev' into v2_admin_mode
This commit is contained in:
@@ -125,7 +125,7 @@ export class OnePanelClient {
|
||||
|
||||
async getAccessToken() {
|
||||
if (this.access.type === "apikey") {
|
||||
return this.getAccessTokenByApiKey();
|
||||
return await this.getAccessTokenByApiKey();
|
||||
} else {
|
||||
return await this.getAccessTokenByPassword();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { IsAccess, AccessInput, BaseAccess } from "@certd/pipeline";
|
||||
import { CtyunClient } from "../lib.js";
|
||||
import { HttpClient } from "@certd/basic";
|
||||
|
||||
@IsAccess({
|
||||
name: "ctyun",
|
||||
@@ -27,6 +29,37 @@ export class CtyunAccess extends BaseAccess {
|
||||
helper: "",
|
||||
})
|
||||
securityKey = "";
|
||||
|
||||
|
||||
|
||||
@AccessInput({
|
||||
title: "测试",
|
||||
component: {
|
||||
name: "api-test",
|
||||
action: "TestRequest",
|
||||
},
|
||||
helper: "点击测试接口看是否正常",
|
||||
})
|
||||
testRequest = true;
|
||||
|
||||
async onTestRequest() {
|
||||
await this.getCdnDomainList()
|
||||
return "ok";
|
||||
}
|
||||
|
||||
async getCdnDomainList() {
|
||||
const http: HttpClient = this.ctx.http;
|
||||
const client = new CtyunClient({
|
||||
access:this,
|
||||
http,
|
||||
logger: this.ctx.logger,
|
||||
});
|
||||
|
||||
// 008 是天翼云的CDN加速域名产品码
|
||||
const all = await client.getDomainList({ productCode: "008" });
|
||||
const list = all || []
|
||||
return list
|
||||
}
|
||||
}
|
||||
|
||||
new CtyunAccess();
|
||||
|
||||
@@ -29,6 +29,40 @@ export class K8sAccess extends BaseAccess {
|
||||
encrypt: false,
|
||||
})
|
||||
skipTLSVerify: boolean;
|
||||
|
||||
|
||||
|
||||
@AccessInput({
|
||||
title: "测试",
|
||||
component: {
|
||||
name: "api-test",
|
||||
action: "TestRequest",
|
||||
},
|
||||
helper: "点击测试接口看是否正常",
|
||||
})
|
||||
testRequest = true;
|
||||
|
||||
async onTestRequest() {
|
||||
|
||||
const k8sClient = await this.getK8sClient()
|
||||
await k8sClient.getSecrets({
|
||||
namespace: "default",
|
||||
})
|
||||
return "ok";
|
||||
}
|
||||
|
||||
async getK8sClient() {
|
||||
const sdk = await import("@certd/lib-k8s");
|
||||
const K8sClient = sdk.K8sClient;
|
||||
|
||||
const k8sClient = new K8sClient({
|
||||
kubeConfigStr: this.kubeconfig,
|
||||
logger: this.ctx.logger,
|
||||
skipTLSVerify: this.skipTLSVerify,
|
||||
});
|
||||
return k8sClient;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
new K8sAccess();
|
||||
|
||||
@@ -30,6 +30,87 @@ export class KuocaiCdnAccess extends BaseAccess {
|
||||
encrypt: true,
|
||||
})
|
||||
password = "";
|
||||
|
||||
|
||||
|
||||
@AccessInput({
|
||||
title: "测试",
|
||||
component: {
|
||||
name: "api-test",
|
||||
action: "TestRequest",
|
||||
},
|
||||
helper: "点击测试接口看是否正常",
|
||||
})
|
||||
testRequest = true;
|
||||
|
||||
async onTestRequest() {
|
||||
const loginRes = await this.getLoginToken();
|
||||
await this.getDomainList(loginRes);
|
||||
return "ok";
|
||||
}
|
||||
|
||||
|
||||
async getLoginToken() {
|
||||
const url = "https://kuocaicdn.com/login/loginUser";
|
||||
const data = {
|
||||
userAccount: this.username,
|
||||
userPwd: this.password,
|
||||
remember: true,
|
||||
};
|
||||
const http = this.ctx.http;
|
||||
const res: any = await http.request({
|
||||
url,
|
||||
method: "POST",
|
||||
data,
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
returnOriginRes: true,
|
||||
});
|
||||
if (!res.data?.success) {
|
||||
throw new Error(res.data?.message);
|
||||
}
|
||||
|
||||
const jsessionId = this.ctx.utils.request.getCookie(res, "JSESSIONID");
|
||||
const token = res.data?.data;
|
||||
return {
|
||||
jsessionId,
|
||||
token,
|
||||
};
|
||||
}
|
||||
|
||||
async getDomainList(loginRes: any) {
|
||||
const url = "https://kuocaicdn.com/CdnDomain/queryForDatatables";
|
||||
const data = {
|
||||
draw: 1,
|
||||
start: 0,
|
||||
length: 1000,
|
||||
search: {
|
||||
value: "",
|
||||
regex: false,
|
||||
},
|
||||
};
|
||||
|
||||
const res = await this.doRequest(url, loginRes, data);
|
||||
return res.data?.data;
|
||||
}
|
||||
|
||||
async doRequest(url: string, loginRes: any, data: any) {
|
||||
const http = this.ctx.http;
|
||||
const res: any = await http.request({
|
||||
url,
|
||||
method: "POST",
|
||||
headers: {
|
||||
Cookie: `JSESSIONID=${loginRes.jsessionId};kuocai_cdn_token=${loginRes.token}`,
|
||||
},
|
||||
data,
|
||||
});
|
||||
if (!res.success) {
|
||||
throw new Error(res.message);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
new KuocaiCdnAccess();
|
||||
|
||||
+4
-64
@@ -54,7 +54,7 @@ export class KuocaiDeployToCDNPlugin extends AbstractTaskPlugin {
|
||||
async onInstance() {}
|
||||
async execute(): Promise<void> {
|
||||
const access = await this.getAccess<KuocaiCdnAccess>(this.accessId);
|
||||
const loginRes = await this.getLoginToken(access);
|
||||
const loginRes = await access.getLoginToken();
|
||||
|
||||
const curl = "https://kuocaicdn.com/CdnDomainHttps/httpsConfiguration";
|
||||
for (const domain of this.domains) {
|
||||
@@ -78,71 +78,11 @@ export class KuocaiDeployToCDNPlugin extends AbstractTaskPlugin {
|
||||
private_key: cert.key,
|
||||
},
|
||||
};
|
||||
await this.doRequest(curl, loginRes, update);
|
||||
await access.doRequest(curl, loginRes, update);
|
||||
this.logger.info(`站点${domain}证书更新成功`);
|
||||
}
|
||||
}
|
||||
|
||||
async getLoginToken(access: KuocaiCdnAccess) {
|
||||
const url = "https://kuocaicdn.com/login/loginUser";
|
||||
const data = {
|
||||
userAccount: access.username,
|
||||
userPwd: access.password,
|
||||
remember: true,
|
||||
};
|
||||
const http = this.ctx.http;
|
||||
const res: any = await http.request({
|
||||
url,
|
||||
method: "POST",
|
||||
data,
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
returnOriginRes: true,
|
||||
});
|
||||
if (!res.data?.success) {
|
||||
throw new Error(res.data?.message);
|
||||
}
|
||||
|
||||
const jsessionId = this.ctx.utils.request.getCookie(res, "JSESSIONID");
|
||||
const token = res.data?.data;
|
||||
return {
|
||||
jsessionId,
|
||||
token,
|
||||
};
|
||||
}
|
||||
|
||||
async getDomainList(loginRes: any) {
|
||||
const url = "https://kuocaicdn.com/CdnDomain/queryForDatatables";
|
||||
const data = {
|
||||
draw: 1,
|
||||
start: 0,
|
||||
length: 1000,
|
||||
search: {
|
||||
value: "",
|
||||
regex: false,
|
||||
},
|
||||
};
|
||||
|
||||
const res = await this.doRequest(url, loginRes, data);
|
||||
return res.data?.data;
|
||||
}
|
||||
|
||||
private async doRequest(url: string, loginRes: any, data: any) {
|
||||
const http = this.ctx.http;
|
||||
const res: any = await http.request({
|
||||
url,
|
||||
method: "POST",
|
||||
headers: {
|
||||
Cookie: `JSESSIONID=${loginRes.jsessionId};kuocai_cdn_token=${loginRes.token}`,
|
||||
},
|
||||
data,
|
||||
});
|
||||
if (!res.success) {
|
||||
throw new Error(res.message);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
async onGetDomainList(data: any) {
|
||||
if (!this.accessId) {
|
||||
@@ -150,9 +90,9 @@ export class KuocaiDeployToCDNPlugin extends AbstractTaskPlugin {
|
||||
}
|
||||
const access = await this.getAccess<KuocaiCdnAccess>(this.accessId);
|
||||
|
||||
const loginRes = await this.getLoginToken(access);
|
||||
const loginRes = await access.getLoginToken();
|
||||
|
||||
const list = await this.getDomainList(loginRes);
|
||||
const list = await access.getDomainList(loginRes);
|
||||
|
||||
if (!list || list.length === 0) {
|
||||
throw new Error("您账户下还没有站点域名,请先添加域名");
|
||||
|
||||
@@ -85,6 +85,90 @@ export class LeCDNAccess extends BaseAccess {
|
||||
`,
|
||||
})
|
||||
apiToken = "";
|
||||
|
||||
|
||||
@AccessInput({
|
||||
title: "测试",
|
||||
component: {
|
||||
name: "api-test",
|
||||
action: "TestRequest",
|
||||
},
|
||||
helper: "点击测试接口看是否正常",
|
||||
})
|
||||
testRequest = true;
|
||||
|
||||
_token: string;
|
||||
|
||||
async onTestRequest() {
|
||||
await this.getCerts();
|
||||
return "ok";
|
||||
}
|
||||
|
||||
|
||||
|
||||
async getCerts() {
|
||||
// http://cdnadmin.kxfox.com/prod-api/certificate?current_page=1&total=3&page_size=10
|
||||
return await this.doRequest({
|
||||
url: `/prod-api/certificate`,
|
||||
method: "get",
|
||||
params: {
|
||||
current_page: 1,
|
||||
page_size: 1000,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async doRequest(config: any) {
|
||||
|
||||
const token = await this.getToken();
|
||||
const access = this;
|
||||
const Authorization = access.type === "token" ? access.apiToken : `Bearer ${token}`;
|
||||
const res = await this.ctx.http.request({
|
||||
baseURL: access.url,
|
||||
headers: {
|
||||
Authorization,
|
||||
},
|
||||
...config,
|
||||
});
|
||||
this.checkRes(res);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
|
||||
async getToken() {
|
||||
if (this.type === "token") {
|
||||
return this.apiToken;
|
||||
}
|
||||
if (this._token){
|
||||
return this._token;
|
||||
}
|
||||
// http://cdnadmin.kxfox.com/prod-api/login
|
||||
const access = this;
|
||||
const res = await this.ctx.http.request({
|
||||
url: `/prod-api/login`,
|
||||
baseURL: access.url,
|
||||
method: "post",
|
||||
data: {
|
||||
//新旧版本不一样,旧版本是username,新版本是email
|
||||
email: access.username,
|
||||
username: access.username,
|
||||
password: access.password,
|
||||
},
|
||||
});
|
||||
this.checkRes(res);
|
||||
//新旧版本不一样,旧版本是access_token,新版本是token
|
||||
const token = res.data.access_token || res.data.token;
|
||||
|
||||
this._token = token;
|
||||
return token;
|
||||
}
|
||||
|
||||
private checkRes(res: any) {
|
||||
if (res.code !== 0 && res.code !== 200) {
|
||||
throw new Error(res.message || JSON.stringify(res));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
new LeCDNAccess();
|
||||
|
||||
+5
-55
@@ -58,49 +58,15 @@ export class LeCDNUpdateCertV2 extends AbstractTaskPlugin {
|
||||
|
||||
async onInstance() {
|
||||
this.access = await this.getAccess<LeCDNAccess>(this.accessId);
|
||||
this.token = await this.getToken();
|
||||
this.access.getToken();
|
||||
}
|
||||
|
||||
async doRequest(config: any) {
|
||||
const access = this.access;
|
||||
const Authorization = this.access.type === "token" ? this.access.apiToken : `Bearer ${this.token}`;
|
||||
const res = await this.ctx.http.request({
|
||||
baseURL: access.url,
|
||||
headers: {
|
||||
Authorization,
|
||||
},
|
||||
...config,
|
||||
});
|
||||
this.checkRes(res);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
async getToken() {
|
||||
if (this.access.type === "token") {
|
||||
return this.access.apiToken;
|
||||
}
|
||||
// http://cdnadmin.kxfox.com/prod-api/login
|
||||
const access = this.access;
|
||||
const res = await this.ctx.http.request({
|
||||
url: `/prod-api/login`,
|
||||
baseURL: access.url,
|
||||
method: "post",
|
||||
data: {
|
||||
//新旧版本不一样,旧版本是username,新版本是email
|
||||
email: access.username,
|
||||
username: access.username,
|
||||
password: access.password,
|
||||
},
|
||||
});
|
||||
this.checkRes(res);
|
||||
//新旧版本不一样,旧版本是access_token,新版本是token
|
||||
return res.data.access_token || res.data.token;
|
||||
}
|
||||
|
||||
async getCertInfo(id: number) {
|
||||
// http://cdnadmin.kxfox.com/prod-api/certificate/9
|
||||
// Bearer edGkiOiIJ8
|
||||
return await this.doRequest({
|
||||
return await this.access.doRequest({
|
||||
url: `/prod-api/certificate/${id}`,
|
||||
method: "get",
|
||||
});
|
||||
@@ -117,7 +83,7 @@ export class LeCDNUpdateCertV2 extends AbstractTaskPlugin {
|
||||
|
||||
this.logger.info(`证书名称:${certInfo.name}`);
|
||||
|
||||
return await this.doRequest({
|
||||
return await this.access.doRequest({
|
||||
url: `/prod-api/certificate/${id}`,
|
||||
method: "put",
|
||||
data: certInfo,
|
||||
@@ -134,17 +100,13 @@ export class LeCDNUpdateCertV2 extends AbstractTaskPlugin {
|
||||
this.logger.info(`更新证书完成`);
|
||||
}
|
||||
|
||||
private checkRes(res: any) {
|
||||
if (res.code !== 0 && res.code !== 200) {
|
||||
throw new Error(res.message || JSON.stringify(res));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async onGetCertList(data: any) {
|
||||
if (!this.accessId) {
|
||||
throw new Error("请选择Access授权");
|
||||
}
|
||||
const res = await this.getCerts();
|
||||
const res = await this.access.getCerts();
|
||||
//新旧版本不一样,一个data 一个是items
|
||||
const list = res.items || res.data;
|
||||
if (!res || list.length === 0) {
|
||||
@@ -158,18 +120,6 @@ export class LeCDNUpdateCertV2 extends AbstractTaskPlugin {
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private async getCerts() {
|
||||
// http://cdnadmin.kxfox.com/prod-api/certificate?current_page=1&total=3&page_size=10
|
||||
return await this.doRequest({
|
||||
url: `/prod-api/certificate`,
|
||||
method: "get",
|
||||
params: {
|
||||
current_page: 1,
|
||||
page_size: 1000,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
new LeCDNUpdateCertV2();
|
||||
|
||||
@@ -49,6 +49,62 @@ export class LuckyAccess extends BaseAccess {
|
||||
encrypt: true,
|
||||
})
|
||||
openToken = "";
|
||||
|
||||
|
||||
@AccessInput({
|
||||
title: "测试",
|
||||
component: {
|
||||
name: "api-test",
|
||||
action: "TestRequest",
|
||||
},
|
||||
helper: "点击测试接口看是否正常",
|
||||
})
|
||||
testRequest = true;
|
||||
|
||||
async onTestRequest() {
|
||||
await this.getCertList();
|
||||
return "ok";
|
||||
}
|
||||
|
||||
|
||||
async doRequest(req: { urlPath: string; data: any; method?: string }) {
|
||||
const { urlPath, data, method } = req;
|
||||
let url = `${this.url}/${this.safePath || ""}${urlPath}?_=${Math.floor(new Date().getTime())}`;
|
||||
// 从第7个字符起,将//替换成/
|
||||
const protocol = url.substring(0, 7);
|
||||
let suffix = url.substring(7);
|
||||
suffix = suffix.replaceAll("//", "/");
|
||||
suffix = suffix.replaceAll("//", "/");
|
||||
url = protocol + suffix;
|
||||
|
||||
const headers: any = {
|
||||
// Origin: access.url,
|
||||
"Content-Type": "application/json",
|
||||
// "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.95 Safari/537.36",
|
||||
};
|
||||
headers["openToken"] = this.openToken;
|
||||
const res = await this.ctx.http.request({
|
||||
method: method || "POST",
|
||||
url,
|
||||
data,
|
||||
headers,
|
||||
skipSslVerify: true,
|
||||
});
|
||||
if (res.ret !== 0) {
|
||||
throw new Error(`请求失败:${res.msg}`);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
async getCertList() {
|
||||
const res = await this.doRequest({
|
||||
urlPath: "/api/ssl",
|
||||
data: {},
|
||||
method: "GET",
|
||||
});
|
||||
const list = res.list || [];
|
||||
return list
|
||||
}
|
||||
}
|
||||
|
||||
new LuckyAccess();
|
||||
|
||||
@@ -82,8 +82,7 @@ export class LuckyUpdateCert extends AbstractPlusTaskPlugin {
|
||||
throw new Error(`没有找到证书:Key=${item},请确认该证书是否存在`);
|
||||
}
|
||||
const remark = old.Remark;
|
||||
const res = await this.doRequest({
|
||||
access,
|
||||
const res = await access.doRequest({
|
||||
urlPath: "/api/ssl",
|
||||
method: "PUT",
|
||||
data: {
|
||||
@@ -107,44 +106,9 @@ export class LuckyUpdateCert extends AbstractPlusTaskPlugin {
|
||||
this.logger.info("部署成功");
|
||||
}
|
||||
|
||||
async doRequest(req: { access: LuckyAccess; urlPath: string; data: any; method?: string }) {
|
||||
const { access, urlPath, data, method } = req;
|
||||
let url = `${access.url}/${access.safePath || ""}${urlPath}?_=${Math.floor(new Date().getTime())}`;
|
||||
// 从第7个字符起,将//替换成/
|
||||
const protocol = url.substring(0, 7);
|
||||
let suffix = url.substring(7);
|
||||
suffix = suffix.replaceAll("//", "/");
|
||||
suffix = suffix.replaceAll("//", "/");
|
||||
url = protocol + suffix;
|
||||
|
||||
const headers: any = {
|
||||
// Origin: access.url,
|
||||
"Content-Type": "application/json",
|
||||
// "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.95 Safari/537.36",
|
||||
};
|
||||
headers["openToken"] = access.openToken;
|
||||
const res = await this.http.request({
|
||||
method: method || "POST",
|
||||
url,
|
||||
data,
|
||||
headers,
|
||||
skipSslVerify: true,
|
||||
});
|
||||
if (res.ret !== 0) {
|
||||
throw new Error(`请求失败:${res.msg}`);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
async onGetCertList() {
|
||||
const access: LuckyAccess = await this.getAccess<LuckyAccess>(this.accessId);
|
||||
const res = await this.doRequest({
|
||||
access,
|
||||
urlPath: "/api/ssl",
|
||||
data: {},
|
||||
method: "GET",
|
||||
});
|
||||
const list = res.list;
|
||||
const list = await access.getCertList();
|
||||
if (!list || list.length === 0) {
|
||||
throw new Error("没有找到证书,请先在SSL/TLS证书页面中手动上传一次证书");
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { IsAccess, AccessInput, BaseAccess } from "@certd/pipeline";
|
||||
import { MaoyunClient } from "@certd/plugin-plus";
|
||||
|
||||
/**
|
||||
*/
|
||||
@@ -49,6 +50,45 @@ export class MaoyunAccess extends BaseAccess {
|
||||
required: false,
|
||||
})
|
||||
httpProxy!: string;
|
||||
|
||||
@AccessInput({
|
||||
title: "测试",
|
||||
component: {
|
||||
name: "api-test",
|
||||
action: "TestRequest",
|
||||
},
|
||||
helper: "点击测试接口看是否正常",
|
||||
})
|
||||
testRequest = true;
|
||||
|
||||
async onTestRequest() {
|
||||
await this.getCdnDomainList();
|
||||
return "ok";
|
||||
}
|
||||
|
||||
async getCdnDomainList() {
|
||||
const client = new MaoyunClient({
|
||||
http: this.ctx.http,
|
||||
logger: this.ctx.logger,
|
||||
access: this,
|
||||
});
|
||||
await client.login();
|
||||
const res = await client.doRequest({
|
||||
url: "/cdn/domain",
|
||||
data: {},
|
||||
params: {
|
||||
channel_type: "0,1,2",
|
||||
page: 1,
|
||||
page_size: 1000,
|
||||
},
|
||||
method: "GET",
|
||||
});
|
||||
const list = res.data || [];
|
||||
return list
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
new MaoyunAccess();
|
||||
|
||||
+1
-17
@@ -115,23 +115,7 @@ export class MaoyunDeployToCdn extends AbstractPlusTaskPlugin {
|
||||
|
||||
async onGetDomainList() {
|
||||
const access: MaoyunAccess = await this.getAccess<MaoyunAccess>(this.accessId);
|
||||
const client = new MaoyunClient({
|
||||
http: this.ctx.http,
|
||||
logger: this.logger,
|
||||
access,
|
||||
});
|
||||
await client.login();
|
||||
const res = await client.doRequest({
|
||||
url: "/cdn/domain",
|
||||
data: {},
|
||||
params: {
|
||||
channel_type: "0,1,2",
|
||||
page: 1,
|
||||
page_size: 1000,
|
||||
},
|
||||
method: "GET",
|
||||
});
|
||||
const list = res.data;
|
||||
const list = await access.getCdnDomainList();
|
||||
if (!list || list.length === 0) {
|
||||
throw new Error("没有找到加速域名,请先在控制台添加加速域名");
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { HttpRequestConfig } from "@certd/basic";
|
||||
import { IsAccess, AccessInput, BaseAccess } from "@certd/pipeline";
|
||||
|
||||
/**
|
||||
@@ -40,6 +41,48 @@ export class SafelineAccess extends BaseAccess {
|
||||
helper: "如果面板的url是https,且使用的是自签名证书,则需要开启此选项,其他情况可以关闭",
|
||||
})
|
||||
skipSslVerify = true;
|
||||
|
||||
@AccessInput({
|
||||
title: "测试",
|
||||
component: {
|
||||
name: "api-test",
|
||||
action: "onTestRequest",
|
||||
},
|
||||
helper: "点击测试接口看是否正常",
|
||||
})
|
||||
testRequest = true;
|
||||
|
||||
async onTestRequest() {
|
||||
await this.getCertList();
|
||||
return "ok";
|
||||
}
|
||||
|
||||
async getCertList() {
|
||||
const res = await this.doRequest({
|
||||
url: "/api/open/cert",
|
||||
method: "get",
|
||||
data: {},
|
||||
});
|
||||
const nodes = res?.nodes || [];
|
||||
return nodes
|
||||
}
|
||||
|
||||
|
||||
async doRequest(config: HttpRequestConfig<any>) {
|
||||
config.baseURL = this.baseUrl;
|
||||
config.skipSslVerify = this.skipSslVerify ?? false;
|
||||
config.logRes = false;
|
||||
config.logParams = false;
|
||||
config.headers = {
|
||||
"X-SLCE-API-TOKEN": this.apiToken,
|
||||
};
|
||||
const res = await this.ctx.http.request(config);
|
||||
if (!res.err) {
|
||||
return res.data;
|
||||
}
|
||||
throw new Error(res.msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
new SafelineAccess();
|
||||
|
||||
+4
-18
@@ -1,9 +1,8 @@
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
|
||||
import { HttpRequestConfig } from "@certd/basic";
|
||||
|
||||
import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert";
|
||||
import { SafelineAccess } from "../access.js";
|
||||
import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "@certd/plugin-lib";
|
||||
import { SafelineAccess } from "../access.js";
|
||||
|
||||
@IsTaskPlugin({
|
||||
name: "SafelineDeployToWebsitePlugin",
|
||||
@@ -83,7 +82,7 @@ export class SafelineDeployToWebsitePlugin extends AbstractTaskPlugin {
|
||||
data.id = parseInt(certId)
|
||||
type = "更新"
|
||||
}
|
||||
const res = await this.doRequest({
|
||||
const res = await this.access.doRequest({
|
||||
url: "/api/open/cert",
|
||||
method: "post",
|
||||
data:data
|
||||
@@ -91,25 +90,12 @@ export class SafelineDeployToWebsitePlugin extends AbstractTaskPlugin {
|
||||
this.logger.info(`证书<${certId}>${type}成功,ID:${res}`);
|
||||
}
|
||||
|
||||
async doRequest(config: HttpRequestConfig<any>) {
|
||||
config.baseURL = this.access.baseUrl;
|
||||
config.skipSslVerify = this.access.skipSslVerify ?? false;
|
||||
config.logRes = false;
|
||||
config.logParams = false;
|
||||
config.headers = {
|
||||
"X-SLCE-API-TOKEN": this.access.apiToken,
|
||||
};
|
||||
const res = await this.ctx.http.request(config);
|
||||
if (!res.err) {
|
||||
return res.data;
|
||||
}
|
||||
throw new Error(res.msg);
|
||||
}
|
||||
|
||||
|
||||
// requestHandle
|
||||
|
||||
async onGetCertIds() {
|
||||
const res = await this.doRequest({
|
||||
const res = await this.access.doRequest({
|
||||
url: "/api/open/cert",
|
||||
method: "get",
|
||||
data: {},
|
||||
|
||||
@@ -124,6 +124,23 @@ export class SynologyAccess extends BaseAccess {
|
||||
})
|
||||
timeout = 120;
|
||||
|
||||
@AccessInput({
|
||||
title: "测试",
|
||||
component: {
|
||||
name: "api-test",
|
||||
action: "onTestRequest",
|
||||
},
|
||||
helper: "点击测试接口看是否正常",
|
||||
})
|
||||
testRequest = true;
|
||||
|
||||
async onTestRequest() {
|
||||
const client = new SynologyClient(this as any, this.ctx.http, this.ctx.logger, this.skipSslVerify);
|
||||
await client.doLogin();
|
||||
await client.getCertList();
|
||||
return "ok";
|
||||
}
|
||||
|
||||
onLoginWithOPTCode(data: { otpCode: string }) {
|
||||
const ctx = this.ctx;
|
||||
const client = new SynologyClient(this as any, ctx.http, ctx.logger, this.skipSslVerify);
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export * from "./plugin-deploy-to-panel.js";
|
||||
export * from "./plugin-keep-alive.js";
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ export class SynologyDeployToPanel extends AbstractPlusTaskPlugin {
|
||||
//授权选择框
|
||||
@TaskInput({
|
||||
title: "群晖授权",
|
||||
helper: "群晖登录授权,请确保账户是管理员用户组",
|
||||
helper: "群晖登录授权,请确保账户是管理员用户组\n群晖OTP授权有效期只有30天,您还需要添加“群晖-刷新OTP登录有效期”任务做登录有效期保活",
|
||||
component: {
|
||||
name: "access-selector",
|
||||
type: "synology",
|
||||
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskOutput } from "@certd/pipeline";
|
||||
import { AbstractPlusTaskPlugin, SynologyClient } from "@certd/plugin-plus";
|
||||
import dayjs from "dayjs";
|
||||
import { SynologyAccess } from "../access.js";
|
||||
@IsTaskPlugin({
|
||||
name: "SynologyKeepAlive",
|
||||
title: "群晖-刷新OTP登录有效期",
|
||||
icon: "simple-icons:synology",
|
||||
group: pluginGroups.panel.key,
|
||||
desc: "群晖登录状态可能30天失效,需要在失效之前登录一次,刷新有效期,您可以将其放在“部署到群晖面板”任务之后",
|
||||
showRunStrategy: false,
|
||||
default: {
|
||||
strategy: {
|
||||
runStrategy: RunStrategy.AlwaysRun,
|
||||
},
|
||||
},
|
||||
needPlus: true,
|
||||
})
|
||||
export class SynologyKeepAlivePlugin extends AbstractPlusTaskPlugin {
|
||||
|
||||
|
||||
@TaskInput({
|
||||
title: "群晖授权",
|
||||
helper: "群晖登录授权,请确保账户是管理员用户组",
|
||||
component: {
|
||||
name: "access-selector",
|
||||
type: "synology",
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
accessId!: string;
|
||||
|
||||
|
||||
//授权选择框
|
||||
@TaskInput({
|
||||
title: "间隔天数",
|
||||
helper: "多少天刷新一次,建议15天以内",
|
||||
value: 15,
|
||||
component: {
|
||||
name: "a-input-number",
|
||||
vModel:"value",
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
intervalDays!: number;
|
||||
|
||||
@TaskOutput({
|
||||
title: "上次刷新时间",
|
||||
type :"SynologyLastRefreshTime"
|
||||
})
|
||||
lastRefreshTime!: number;
|
||||
|
||||
async onInstance() {}
|
||||
async execute(): Promise<any> {
|
||||
this.logger.info("开始刷新群晖登录有效期");
|
||||
const now = dayjs()
|
||||
const status = this.getLastStatus();
|
||||
if (status) {
|
||||
let lastRefreshTime = this.getLastOutput("lastRefreshTime");
|
||||
lastRefreshTime = lastRefreshTime || 0;
|
||||
this.lastRefreshTime = lastRefreshTime;
|
||||
const lastTime = dayjs(lastRefreshTime);
|
||||
const diffDays = now.diff(lastTime, "day");
|
||||
|
||||
this.logger.info(`上次刷新时间${lastTime.format("YYYY-MM-DD")}`);
|
||||
if (diffDays < this.intervalDays) {
|
||||
this.logger.info(`距离上次刷新${diffDays}天,不足${this.intervalDays}天,无需刷新`);
|
||||
this.logger.info(`下一次刷新时间${lastTime.add(this.intervalDays, "day").format("YYYY-MM-DD")}`);
|
||||
return "skip";
|
||||
}else{
|
||||
this.logger.info(`超过${this.intervalDays}天,需要刷新`);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const access: SynologyAccess = await this.getAccess<SynologyAccess>(this.accessId);
|
||||
const client = new SynologyClient(access as any, this.ctx.http, this.ctx.logger, access.skipSslVerify);
|
||||
await client.doLogin();
|
||||
await client.getCertList();
|
||||
this.lastRefreshTime = now.valueOf();
|
||||
this.logger.info("刷新群晖登录有效期成功");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
new SynologyKeepAlivePlugin();
|
||||
@@ -1,4 +1,5 @@
|
||||
import { IsAccess, AccessInput, BaseAccess } from "@certd/pipeline";
|
||||
import { UniCloudClient } from "@certd/plugin-plus";
|
||||
|
||||
/**
|
||||
*/
|
||||
@@ -29,6 +30,28 @@ export class UniCloudAccess extends BaseAccess {
|
||||
encrypt: true,
|
||||
})
|
||||
password = "";
|
||||
|
||||
// await this.getToken();
|
||||
|
||||
@AccessInput({
|
||||
title: "测试",
|
||||
component: {
|
||||
name: "api-test",
|
||||
action: "onTestRequest",
|
||||
},
|
||||
helper: "点击测试接口看是否正常",
|
||||
})
|
||||
testRequest = true;
|
||||
|
||||
async onTestRequest() {
|
||||
const client = new UniCloudClient({
|
||||
access: this,
|
||||
logger: this.ctx.logger,
|
||||
http: this.ctx.http,
|
||||
});
|
||||
await client.getToken();
|
||||
return "ok";
|
||||
}
|
||||
}
|
||||
|
||||
new UniCloudAccess();
|
||||
|
||||
@@ -30,6 +30,85 @@ export class YidunRcdnAccess extends BaseAccess {
|
||||
encrypt: true,
|
||||
})
|
||||
password = "";
|
||||
|
||||
|
||||
@AccessInput({
|
||||
title: "测试",
|
||||
component: {
|
||||
name: "api-test",
|
||||
action: "onTestRequest",
|
||||
},
|
||||
helper: "点击测试接口看是否正常",
|
||||
})
|
||||
testRequest = true;
|
||||
|
||||
async onTestRequest() {
|
||||
const token = await this.getLoginToken();
|
||||
await this.getDomainList(token);
|
||||
return "ok";
|
||||
}
|
||||
|
||||
async getDomainList(loginRes: any) {
|
||||
const url = "https://rhcdn.yiduncdn.com/CdnDomain/queryForDatatables";
|
||||
const data = {
|
||||
draw: 1,
|
||||
start: 0,
|
||||
length: 1000,
|
||||
search: {
|
||||
value: "",
|
||||
regex: false,
|
||||
},
|
||||
};
|
||||
|
||||
const res = await this.doRequest(url, loginRes, data);
|
||||
return res.data?.data;
|
||||
}
|
||||
|
||||
async doRequest(url: string, loginRes: any, data: any) {
|
||||
const http = this.ctx.http;
|
||||
const res: any = await http.request({
|
||||
url,
|
||||
method: "POST",
|
||||
headers: {
|
||||
Cookie: `JSESSIONID=${loginRes.jsessionId};kuocai_cdn_token=${loginRes.token}`,
|
||||
},
|
||||
data,
|
||||
});
|
||||
if (!res.success) {
|
||||
throw new Error(res.message);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
async getLoginToken() {
|
||||
const access: YidunRcdnAccess = this
|
||||
const url = "https://rhcdn.yiduncdn.com/login/loginUser";
|
||||
const data = {
|
||||
userAccount: access.username,
|
||||
userPwd: access.password,
|
||||
remember: true,
|
||||
};
|
||||
const http = this.ctx.http;
|
||||
const res: any = await http.request({
|
||||
url,
|
||||
method: "POST",
|
||||
data,
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
returnOriginRes: true,
|
||||
});
|
||||
if (!res.data?.success) {
|
||||
throw new Error(res.data?.message);
|
||||
}
|
||||
|
||||
const jsessionId = this.ctx.utils.request.getCookie(res, "JSESSIONID");
|
||||
const token = res.data?.data;
|
||||
return {
|
||||
jsessionId,
|
||||
token,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
new YidunRcdnAccess();
|
||||
|
||||
@@ -32,6 +32,47 @@ export class YidunAccess extends BaseAccess {
|
||||
encrypt: true,
|
||||
})
|
||||
apiSecret = "";
|
||||
|
||||
@AccessInput({
|
||||
title: "测试",
|
||||
component: {
|
||||
name: "api-test",
|
||||
action: "onTestRequest",
|
||||
},
|
||||
helper: "点击测试接口看是否正常",
|
||||
})
|
||||
testRequest = true;
|
||||
|
||||
async onTestRequest() {
|
||||
await this.getDomainList();
|
||||
return "ok";
|
||||
}
|
||||
|
||||
async getDomainList(){
|
||||
const siteUrl = "http://user.yiduncdn.com/v1/sites";
|
||||
const res = await this.doRequest(siteUrl, "GET", { });
|
||||
return res.data
|
||||
}
|
||||
|
||||
async doRequest(url: string, method: string, data: any) {
|
||||
const access = this
|
||||
const { apiKey, apiSecret } = access;
|
||||
const http = this.ctx.http;
|
||||
const res: any = await http.request({
|
||||
url,
|
||||
method,
|
||||
headers: {
|
||||
"api-key": apiKey,
|
||||
"api-secret": apiSecret,
|
||||
},
|
||||
data,
|
||||
});
|
||||
if (res.code != 0) {
|
||||
throw new Error(res.msg);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
new YidunAccess();
|
||||
|
||||
+16
-25
@@ -1,5 +1,6 @@
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
|
||||
import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert";
|
||||
import { YidunAccess } from "../access.js";
|
||||
|
||||
@IsTaskPlugin({
|
||||
name: "YidunDeployToCDN",
|
||||
@@ -60,7 +61,11 @@ export class YidunDeployToCDNPlugin extends AbstractTaskPlugin {
|
||||
})
|
||||
accessId!: string;
|
||||
|
||||
async onInstance() {}
|
||||
access!: YidunAccess;
|
||||
|
||||
async onInstance() {
|
||||
this.access = await this.getAccess<YidunAccess>(this.accessId);
|
||||
}
|
||||
async execute(): Promise<void> {
|
||||
const { domain, certId, cert } = this;
|
||||
if (!domain && !certId) {
|
||||
@@ -77,35 +82,21 @@ export class YidunDeployToCDNPlugin extends AbstractTaskPlugin {
|
||||
private async updateByCertId(cert: CertInfo, certId: number) {
|
||||
this.logger.info(`更新证书,证书ID:${certId}`);
|
||||
const url = `http://user.yiduncdn.com/v1/certs/${certId}`;
|
||||
await this.doRequest(url, "PUT", {
|
||||
|
||||
const access = await this.getAccess<YidunAccess>(this.accessId);
|
||||
|
||||
await access.doRequest(url, "PUT", {
|
||||
cert: cert.crt,
|
||||
key: cert.key,
|
||||
});
|
||||
}
|
||||
|
||||
async doRequest(url: string, method: string, data: any) {
|
||||
const access = await this.getAccess(this.accessId);
|
||||
const { apiKey, apiSecret } = access;
|
||||
const http = this.ctx.http;
|
||||
const res: any = await http.request({
|
||||
url,
|
||||
method,
|
||||
headers: {
|
||||
"api-key": apiKey,
|
||||
"api-secret": apiSecret,
|
||||
},
|
||||
data,
|
||||
});
|
||||
if (res.code != 0) {
|
||||
throw new Error(res.msg);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
private async updateByDomain(cert: CertInfo) {
|
||||
//查询站点
|
||||
const siteUrl = "http://user.yiduncdn.com/v1/sites";
|
||||
const res = await this.doRequest(siteUrl, "GET", { domain: this.domain });
|
||||
const access = this.access
|
||||
const res = await access.doRequest(siteUrl, "GET", { domain: this.domain });
|
||||
if (res.data.length === 0) {
|
||||
throw new Error(`未找到域名相关站点:${this.domain}`);
|
||||
}
|
||||
@@ -127,20 +118,20 @@ export class YidunDeployToCDNPlugin extends AbstractTaskPlugin {
|
||||
this.logger.info(`创建证书,域名:${this.domain}`);
|
||||
const certUrl = `http://user.yiduncdn.com/v1/certs`;
|
||||
const name = this.domain + "_" + new Date().getTime();
|
||||
await this.doRequest(certUrl, "POST", {
|
||||
await access.doRequest(certUrl, "POST", {
|
||||
name,
|
||||
type: "custom",
|
||||
cert: cert.crt,
|
||||
key: cert.key,
|
||||
});
|
||||
|
||||
const certs: any = await this.doRequest(certUrl, "GET", {
|
||||
const certs: any = await access.doRequest(certUrl, "GET", {
|
||||
name,
|
||||
});
|
||||
const certId = certs.data[0].id;
|
||||
|
||||
const siteUrl = "http://user.yiduncdn.com/v1/sites";
|
||||
await this.doRequest(siteUrl, "PUT", { id: site.id, https_listen: { cert: certId } });
|
||||
await access.doRequest(siteUrl, "PUT", { id: site.id, https_listen: { cert: certId } });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-63
@@ -54,7 +54,7 @@ export class YidunDeployToRCDNPlugin extends AbstractTaskPlugin {
|
||||
async onInstance() {}
|
||||
async execute(): Promise<void> {
|
||||
const access = await this.getAccess<YidunRcdnAccess>(this.accessId);
|
||||
const loginRes = await this.getLoginToken(access);
|
||||
const loginRes = await access.getLoginToken();
|
||||
|
||||
const curl = "https://rhcdn.yiduncdn.com/CdnDomainHttps/httpsConfiguration";
|
||||
for (const domain of this.domains) {
|
||||
@@ -78,71 +78,14 @@ export class YidunDeployToRCDNPlugin extends AbstractTaskPlugin {
|
||||
private_key: cert.key,
|
||||
},
|
||||
};
|
||||
await this.doRequest(curl, loginRes, update);
|
||||
await access.doRequest(curl, loginRes, update);
|
||||
this.logger.info(`站点${domain}证书更新成功`);
|
||||
}
|
||||
}
|
||||
|
||||
async getLoginToken(access: YidunRcdnAccess) {
|
||||
const url = "https://rhcdn.yiduncdn.com/login/loginUser";
|
||||
const data = {
|
||||
userAccount: access.username,
|
||||
userPwd: access.password,
|
||||
remember: true,
|
||||
};
|
||||
const http = this.ctx.http;
|
||||
const res: any = await http.request({
|
||||
url,
|
||||
method: "POST",
|
||||
data,
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
returnOriginRes: true,
|
||||
});
|
||||
if (!res.data?.success) {
|
||||
throw new Error(res.data?.message);
|
||||
}
|
||||
|
||||
|
||||
const jsessionId = this.ctx.utils.request.getCookie(res, "JSESSIONID");
|
||||
const token = res.data?.data;
|
||||
return {
|
||||
jsessionId,
|
||||
token,
|
||||
};
|
||||
}
|
||||
|
||||
async getDomainList(loginRes: any) {
|
||||
const url = "https://rhcdn.yiduncdn.com/CdnDomain/queryForDatatables";
|
||||
const data = {
|
||||
draw: 1,
|
||||
start: 0,
|
||||
length: 1000,
|
||||
search: {
|
||||
value: "",
|
||||
regex: false,
|
||||
},
|
||||
};
|
||||
|
||||
const res = await this.doRequest(url, loginRes, data);
|
||||
return res.data?.data;
|
||||
}
|
||||
|
||||
private async doRequest(url: string, loginRes: any, data: any) {
|
||||
const http = this.ctx.http;
|
||||
const res: any = await http.request({
|
||||
url,
|
||||
method: "POST",
|
||||
headers: {
|
||||
Cookie: `JSESSIONID=${loginRes.jsessionId};kuocai_cdn_token=${loginRes.token}`,
|
||||
},
|
||||
data,
|
||||
});
|
||||
if (!res.success) {
|
||||
throw new Error(res.message);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
async onGetDomainList(data: any) {
|
||||
if (!this.accessId) {
|
||||
@@ -150,9 +93,9 @@ export class YidunDeployToRCDNPlugin extends AbstractTaskPlugin {
|
||||
}
|
||||
const access = await this.getAccess<YidunRcdnAccess>(this.accessId);
|
||||
|
||||
const loginRes = await this.getLoginToken(access);
|
||||
const loginRes = await access.getLoginToken();
|
||||
|
||||
const list = await this.getDomainList(loginRes);
|
||||
const list = await access.getDomainList(loginRes);
|
||||
|
||||
if (!list || list.length === 0) {
|
||||
throw new Error("您账户下还没有站点域名,请先添加域名");
|
||||
|
||||
Reference in New Issue
Block a user