mirror of
https://github.com/certd/certd.git
synced 2026-07-18 20:17:34 +08:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 32de8d9ccb | |||
| e06da886f7 | |||
| cdd5ad3a8e | |||
| 9bee0e460b | |||
| 60c8ace443 | |||
| 933aaeaf25 | |||
| ca43c77525 | |||
| b204182c13 | |||
| dfb4165a12 | |||
| 26a54cd228 | |||
| e229f14121 |
@@ -3,6 +3,30 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.38.3](https://github.com/certd/certd/compare/v1.38.2...v1.38.3) (2026-01-28)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 当通知配置被删除时,使用默认通知配置进行发送 ([5398300](https://github.com/certd/certd/commit/53983002b6553a929b72e2c70a26809a9f306e89))
|
||||
* 站点检查多个ip连接超时的报错显示不出来的bug ([33b284a](https://github.com/certd/certd/commit/33b284afc0ae6391658d573e32b1ce7765e51cb2))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 部署插件支持ucloud alb ([640950d](https://github.com/certd/certd/commit/640950d4c847c72cae2986e3c2cae10d52a67fdf))
|
||||
* 多个dns 提供商支持导入域名 ([d3c0914](https://github.com/certd/certd/commit/d3c0914ac16db8ac77f9c60285bb20cfab7a3cb0))
|
||||
* 首次使用提示新手教程按钮 ([e054c8f](https://github.com/certd/certd/commit/e054c8fc55063fd96548f1c19049070524a63411))
|
||||
* 输入证书域名时,支持点击导入域名 ([40be424](https://github.com/certd/certd/commit/40be42406c6fd5de11f594fc6913178d9e7d8943))
|
||||
* 所有的dnsprovider 支持导入域名列表 ([9f21b1a](https://github.com/certd/certd/commit/9f21b1a09797d7dab253e4416c538b55fb8f4488))
|
||||
* 优化首页统计数据,饼图替换成证书数量统计 ([9fa1c2e](https://github.com/certd/certd/commit/9fa1c2eb3e55ef630333ae24284aa8b54e3414b6))
|
||||
* 优化首页图标 ([998de0f](https://github.com/certd/certd/commit/998de0f9a031339b019aa7a09e61e994664a8047))
|
||||
* 域名导入任务进度条 ([7058d5c](https://github.com/certd/certd/commit/7058d5cb935cab8c75b98493ed497a22dbe70883))
|
||||
* 站点监控,检查状态挪到前面显示 ([48f1bf0](https://github.com/certd/certd/commit/48f1bf091869b87dd17feaca5efd8680ef741582))
|
||||
* 证书仓库页面增加到期状态查询条件 ([58c3d70](https://github.com/certd/certd/commit/58c3d7087bb66358d896a741e12005f690b2bd5e))
|
||||
* 证书流水线创建域名输入框支持获取域名数据进行选择 ([1d5b1c2](https://github.com/certd/certd/commit/1d5b1c239cf350920eb2eb9fd293af74ef412853))
|
||||
* 支持导入51dns域名 ([7eb9694](https://github.com/certd/certd/commit/7eb96942214aed0dfc9c3c5a669374da67052c49))
|
||||
* ucloud支持部署到alb ([78004bd](https://github.com/certd/certd/commit/78004bdfb552a3b83298fa09d518ca282a529d90))
|
||||
* ucloud支持部署到ulb(alb、clb统一成一个) ([c408687](https://github.com/certd/certd/commit/c408687af7669afe733b5506720ca795555acdce))
|
||||
|
||||
## [1.38.2](https://github.com/certd/certd/compare/v1.38.1...v1.38.2) (2026-01-22)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -70,5 +70,5 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/publishlab/node-acme-client/issues"
|
||||
},
|
||||
"gitHead": "f92dc6a1ad103de9cc184da3b84096943906cb59"
|
||||
"gitHead": "ee6cdfb391568ad8532701a2c37ee53e88e39f75"
|
||||
}
|
||||
|
||||
@@ -47,5 +47,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "f92dc6a1ad103de9cc184da3b84096943906cb59"
|
||||
"gitHead": "ee6cdfb391568ad8532701a2c37ee53e88e39f75"
|
||||
}
|
||||
|
||||
@@ -177,39 +177,40 @@ export function createAxiosService({ logger }: { logger: ILogger }) {
|
||||
},
|
||||
(error: any) => {
|
||||
const status = error.response?.status;
|
||||
let message = "";
|
||||
switch (status) {
|
||||
case 400:
|
||||
error.message = "请求错误";
|
||||
message = "请求错误";
|
||||
break;
|
||||
case 401:
|
||||
error.message = "认证/登录失败";
|
||||
message = "认证/登录失败";
|
||||
break;
|
||||
case 403:
|
||||
error.message = "拒绝访问";
|
||||
message = "拒绝访问";
|
||||
break;
|
||||
case 404:
|
||||
error.message = `请求地址出错`;
|
||||
message = `请求地址出错`;
|
||||
break;
|
||||
case 408:
|
||||
error.message = "请求超时";
|
||||
message = "请求超时";
|
||||
break;
|
||||
case 500:
|
||||
error.message = "服务器内部错误";
|
||||
message = "服务器内部错误";
|
||||
break;
|
||||
case 501:
|
||||
error.message = "服务未实现";
|
||||
message = "服务未实现";
|
||||
break;
|
||||
case 502:
|
||||
error.message = "网关错误";
|
||||
message = "网关错误";
|
||||
break;
|
||||
case 503:
|
||||
error.message = "服务不可用";
|
||||
message = "服务不可用";
|
||||
break;
|
||||
case 504:
|
||||
error.message = "网关超时";
|
||||
message = "网关超时";
|
||||
break;
|
||||
case 505:
|
||||
error.message = "HTTP版本不受支持";
|
||||
message = "HTTP版本不受支持";
|
||||
break;
|
||||
case 302:
|
||||
//重定向
|
||||
@@ -217,9 +218,12 @@ export function createAxiosService({ logger }: { logger: ILogger }) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (status) {
|
||||
message += ` [${status}] `;
|
||||
}
|
||||
|
||||
const errorCode = error.code;
|
||||
let errorMessage = null;
|
||||
let errorMessage = "";
|
||||
if (errorCode === "ECONNABORTED") {
|
||||
errorMessage = "请求连接终止";
|
||||
} else if (errorCode === "ETIMEDOUT") {
|
||||
@@ -231,14 +235,17 @@ export function createAxiosService({ logger }: { logger: ILogger }) {
|
||||
} else if (errorCode === "ENOTFOUND") {
|
||||
errorMessage = "请求地址不存在";
|
||||
}
|
||||
if (errorMessage) {
|
||||
if (error.message) {
|
||||
errorMessage += `,${error.message}`;
|
||||
}
|
||||
error.message = errorMessage;
|
||||
if (errorCode) {
|
||||
errorMessage += ` [${errorCode}] `;
|
||||
}
|
||||
|
||||
logger.error(`请求出错:${errorMessage} status:${error.response?.status || error.code},statusText:${error.response?.statusText || error.code},url:${error.config?.url},method:${error.config?.method}。`);
|
||||
if (message) {
|
||||
errorMessage += `,${message}`;
|
||||
}
|
||||
if (error.message) {
|
||||
errorMessage += `(${error.message})`;
|
||||
}
|
||||
error.message = errorMessage;
|
||||
logger.error(`请求出错:${errorMessage} status:${status},statusText:${error.response?.statusText || error.code},url:${error.config?.url},method:${error.config?.method}。`);
|
||||
logger.error("返回数据:", JSON.stringify(error.response?.data));
|
||||
if (error.response?.data) {
|
||||
const message = error.response.data.message || error.response.data.msg || error.response.data.error;
|
||||
|
||||
@@ -45,5 +45,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "f92dc6a1ad103de9cc184da3b84096943906cb59"
|
||||
"gitHead": "ee6cdfb391568ad8532701a2c37ee53e88e39f75"
|
||||
}
|
||||
|
||||
@@ -465,6 +465,8 @@ export class Executor {
|
||||
|
||||
templateData.errors = errors;
|
||||
templateData.pipelineResult = pipelineResult;
|
||||
templateData.title = subject;
|
||||
templateData.content = content;
|
||||
|
||||
for (const notification of this.pipeline.notifications) {
|
||||
if (!notification.when.includes(when)) {
|
||||
|
||||
@@ -24,5 +24,5 @@
|
||||
"prettier": "^2.8.8",
|
||||
"tslib": "^2.8.1"
|
||||
},
|
||||
"gitHead": "f92dc6a1ad103de9cc184da3b84096943906cb59"
|
||||
"gitHead": "ee6cdfb391568ad8532701a2c37ee53e88e39f75"
|
||||
}
|
||||
|
||||
@@ -31,5 +31,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "f92dc6a1ad103de9cc184da3b84096943906cb59"
|
||||
"gitHead": "ee6cdfb391568ad8532701a2c37ee53e88e39f75"
|
||||
}
|
||||
|
||||
@@ -56,5 +56,5 @@
|
||||
"fetch"
|
||||
]
|
||||
},
|
||||
"gitHead": "f92dc6a1ad103de9cc184da3b84096943906cb59"
|
||||
"gitHead": "ee6cdfb391568ad8532701a2c37ee53e88e39f75"
|
||||
}
|
||||
|
||||
@@ -32,5 +32,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "f92dc6a1ad103de9cc184da3b84096943906cb59"
|
||||
"gitHead": "ee6cdfb391568ad8532701a2c37ee53e88e39f75"
|
||||
}
|
||||
|
||||
@@ -64,5 +64,5 @@
|
||||
"typeorm": "^0.3.11",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "f92dc6a1ad103de9cc184da3b84096943906cb59"
|
||||
"gitHead": "ee6cdfb391568ad8532701a2c37ee53e88e39f75"
|
||||
}
|
||||
|
||||
@@ -46,5 +46,5 @@
|
||||
"typeorm": "^0.3.11",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "f92dc6a1ad103de9cc184da3b84096943906cb59"
|
||||
"gitHead": "ee6cdfb391568ad8532701a2c37ee53e88e39f75"
|
||||
}
|
||||
|
||||
@@ -38,5 +38,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "f92dc6a1ad103de9cc184da3b84096943906cb59"
|
||||
"gitHead": "ee6cdfb391568ad8532701a2c37ee53e88e39f75"
|
||||
}
|
||||
|
||||
@@ -57,5 +57,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "f92dc6a1ad103de9cc184da3b84096943906cb59"
|
||||
"gitHead": "ee6cdfb391568ad8532701a2c37ee53e88e39f75"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<div class="cf-turnstile">
|
||||
<div id="turnstile-container" class="cf-turnstile-container" :data-sitekey="siteKeyRef"></div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { nextTick, onMounted, onUnmounted, ref, watch } from "vue";
|
||||
|
||||
import { loadScript } from "vue-plugin-load-script";
|
||||
const loaded = ref(false);
|
||||
async function loadCaptchaScript() {
|
||||
await loadScript("https://challenges.cloudflare.com/turnstile/v0/api.js");
|
||||
loaded.value = true;
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
name: "CfTurnstileCaptcha",
|
||||
});
|
||||
const emit = defineEmits(["update:modelValue", "change"]);
|
||||
const props = defineProps<{
|
||||
modelValue: any;
|
||||
captchaGet: () => Promise<any>;
|
||||
}>();
|
||||
const captchaRef = ref(null);
|
||||
const siteKeyRef = ref("");
|
||||
const widgetIdRef = ref(null);
|
||||
|
||||
onMounted(async () => {
|
||||
await loadCaptchaScript();
|
||||
await nextTick();
|
||||
const { siteKey } = await props.captchaGet();
|
||||
siteKeyRef.value = siteKey; //这里确定是string类型
|
||||
//@ts-ignore
|
||||
const widgetId = turnstile.render("#turnstile-container", {
|
||||
sitekey: siteKey,
|
||||
size: "flexible",
|
||||
callback: function (token: string) {
|
||||
console.log("turnstile success:", token);
|
||||
emitChange({
|
||||
token: token,
|
||||
});
|
||||
},
|
||||
});
|
||||
widgetIdRef.value = widgetId;
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
//@ts-ignore
|
||||
if (turnstile && widgetIdRef.value) {
|
||||
//@ts-ignore
|
||||
turnstile.remove(widgetIdRef.value);
|
||||
}
|
||||
});
|
||||
|
||||
function checkExpired() {
|
||||
//@ts-ignore
|
||||
if (turnstile && widgetIdRef.value) {
|
||||
//@ts-ignore
|
||||
return turnstile.isExpired(widgetIdRef.value);
|
||||
}
|
||||
}
|
||||
|
||||
function emitChange(value: any) {
|
||||
emit("update:modelValue", value);
|
||||
emit("change", value);
|
||||
}
|
||||
function reset() {
|
||||
// 重置验证码
|
||||
//@ts-ignore
|
||||
if (turnstile && widgetIdRef.value) {
|
||||
//@ts-ignore
|
||||
turnstile.reset(widgetIdRef.value);
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => {
|
||||
return props.modelValue;
|
||||
},
|
||||
value => {
|
||||
if (value == null) {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
defineExpose({
|
||||
reset,
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
.cf-turnstile-container {
|
||||
iframe {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -11,8 +11,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { defineEmits, defineExpose, defineProps, ref, watch } from "vue";
|
||||
import { nanoid } from "nanoid";
|
||||
import { ref, watch } from "vue";
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: any;
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, defineProps, defineEmits, ref, onUnmounted, Ref, watch } from "vue";
|
||||
import { notification } from "ant-design-vue";
|
||||
import { ref, Ref, watch } from "vue";
|
||||
|
||||
import { loadScript } from "vue-plugin-load-script";
|
||||
const loaded = ref(false);
|
||||
|
||||
@@ -455,4 +455,10 @@ h6 {
|
||||
background: #ffecb3;
|
||||
color: #f57c00;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-tag{
|
||||
.fs-icon{
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
@@ -9,9 +9,11 @@
|
||||
<addon-selector v-model:model-value="formState.public.captchaAddonId" addon-type="captcha" from="sys" @selected-change="onAddonChanged" />
|
||||
</a-form-item>
|
||||
<a-form-item v-if="formState.public.captchaType === settingsStore.sysPublic.captchaType" :label="t('certd.sys.setting.captchaTest')">
|
||||
<div class="flex">
|
||||
<CaptchaInput v-model:model-value="captchaTestForm.captcha" class="w-50%"></CaptchaInput>
|
||||
<a-button class="ml-2" type="primary" @click="doCaptchaValidate">后端验证</a-button>
|
||||
<div class="flex items-center">
|
||||
<CaptchaInput v-model:model-value="captchaTestForm.captcha" class="w-60%"></CaptchaInput>
|
||||
<a-button class="ml-2 mr-2" type="primary" @click="doCaptchaValidate">后端验证</a-button>
|
||||
<a-tag v-if="captchaTestForm.pass" color="green" class="flex items-center"> <fs-icon icon="material-symbols:check-circle-rounded"></fs-icon> 校验通过</a-tag>
|
||||
<a-tag v-else class="flex items-center"> <fs-icon icon="material-symbols:info-rounded"></fs-icon> 请先点击验证</a-tag>
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ export default ({ command, mode }) => {
|
||||
host: "0.0.0.0",
|
||||
port: 3008,
|
||||
fs: devServerFs,
|
||||
allowedHosts: ["localhost", "127.0.0.1", "yfy.docmirror.cn"],
|
||||
allowedHosts: ["localhost", "127.0.0.1", "yfy.docmirror.cn", "docmirror.top", "*"],
|
||||
proxy: {
|
||||
// with options
|
||||
"/api": {
|
||||
|
||||
@@ -63,8 +63,10 @@
|
||||
"@certd/plugin-plus": "^1.38.3",
|
||||
"@certd/plus-core": "^1.38.3",
|
||||
"@google-cloud/publicca": "^1.3.0",
|
||||
"@huaweicloud/huaweicloud-sdk-cdn": "^3.1.120",
|
||||
"@huaweicloud/huaweicloud-sdk-core": "^3.1.120",
|
||||
"@huaweicloud/huaweicloud-sdk-cdn": "^3.1.185",
|
||||
"@huaweicloud/huaweicloud-sdk-core": "^3.1.185",
|
||||
"@huaweicloud/huaweicloud-sdk-elb": "^3.1.185",
|
||||
"@huaweicloud/huaweicloud-sdk-iam": "^3.1.185",
|
||||
"@koa/cors": "^5.0.0",
|
||||
"@midwayjs/bootstrap": "3.20.11",
|
||||
"@midwayjs/cache": "3.14.0",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { BaseController, Constants, SysSettingsService } from "@certd/lib-server";
|
||||
import { ALL, Body, Controller, Inject, Post, Provide, Query } from "@midwayjs/core";
|
||||
import { ALL, Body, Controller, Inject, Post, Provide, Query, RequestIP } from "@midwayjs/core";
|
||||
import { Rule, RuleType } from "@midwayjs/validate";
|
||||
import { CaptchaService } from "../../modules/basic/service/captcha-service.js";
|
||||
import { CodeService } from "../../modules/basic/service/code-service.js";
|
||||
@@ -62,7 +62,8 @@ export class BasicController extends BaseController {
|
||||
@Post('/sendSmsCode', { summary: Constants.per.guest })
|
||||
public async sendSmsCode(
|
||||
@Body(ALL)
|
||||
body: SmsCodeReq
|
||||
body: SmsCodeReq,
|
||||
@RequestIP() remoteIp: string
|
||||
) {
|
||||
const opts = {
|
||||
verificationType: body.verificationType,
|
||||
@@ -74,7 +75,7 @@ export class BasicController extends BaseController {
|
||||
// opts.verificationCodeLength = 6; //部分厂商这里会设置参数长度这里就不改了
|
||||
}
|
||||
|
||||
await this.codeService.checkCaptcha(body.captcha);
|
||||
await this.codeService.checkCaptcha(body.captcha,{remoteIp});
|
||||
await this.codeService.sendSmsCode(body.phoneCode, body.mobile, opts);
|
||||
return this.ok(null);
|
||||
}
|
||||
@@ -82,7 +83,8 @@ export class BasicController extends BaseController {
|
||||
@Post('/sendEmailCode', { summary: Constants.per.guest })
|
||||
public async sendEmailCode(
|
||||
@Body(ALL)
|
||||
body: EmailCodeReq
|
||||
body: EmailCodeReq,
|
||||
@RequestIP() remoteIp: string
|
||||
) {
|
||||
const opts = {
|
||||
verificationType: body.verificationType,
|
||||
@@ -99,7 +101,7 @@ export class BasicController extends BaseController {
|
||||
}
|
||||
|
||||
|
||||
await this.codeService.checkCaptcha(body.captcha);
|
||||
await this.codeService.checkCaptcha(body.captcha,{remoteIp});
|
||||
await this.codeService.sendEmailCode(body.email, opts);
|
||||
// 设置缓存内容
|
||||
return this.ok(null);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ALL, Body, Controller, Inject, Post, Provide } from "@midwayjs/core";
|
||||
import { ALL, Body, Controller, Inject, Post, Provide, RequestIP } from "@midwayjs/core";
|
||||
import { LoginService } from "../../../modules/login/service/login-service.js";
|
||||
import { AddonService, BaseController, Constants, SysPublicSettings, SysSettingsService } from "@certd/lib-server";
|
||||
import { CodeService } from "../../../modules/basic/service/code-service.js";
|
||||
@@ -26,11 +26,13 @@ export class LoginController extends BaseController {
|
||||
@Post('/login', { summary: Constants.per.guest })
|
||||
public async login(
|
||||
@Body(ALL)
|
||||
body: any
|
||||
body: any,
|
||||
@RequestIP()
|
||||
remoteIp: string
|
||||
) {
|
||||
const settings = await this.sysSettingsService.getPublicSettings()
|
||||
if (settings.captchaEnabled === true) {
|
||||
await this.captchaService.doValidate({form:body.captcha,must:false,captchaAddonId:settings.captchaAddonId})
|
||||
await this.captchaService.doValidate({form:body.captcha,must:false,captchaAddonId:settings.captchaAddonId,req:{remoteIp}})
|
||||
}
|
||||
const token = await this.loginService.loginByPassword(body);
|
||||
this.writeTokenCookie(token);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core';
|
||||
import { ALL, Body, Controller, Inject, Post, Provide, RequestIP } from '@midwayjs/core';
|
||||
import { BaseController, Constants, SysSettingsService } from '@certd/lib-server';
|
||||
import { RegisterType, UserService } from '../../../modules/sys/authority/service/user-service.js';
|
||||
import { CodeService } from '../../../modules/basic/service/code-service.js';
|
||||
@@ -32,7 +32,8 @@ export class RegisterController extends BaseController {
|
||||
@Post('/register', { summary: Constants.per.guest })
|
||||
public async register(
|
||||
@Body(ALL)
|
||||
body: RegisterReq
|
||||
body: RegisterReq,
|
||||
@RequestIP() remoteIp: string
|
||||
) {
|
||||
const sysPublicSettings = await this.sysSettingsService.getPublicSettings();
|
||||
if (sysPublicSettings.registerEnabled === false) {
|
||||
@@ -51,7 +52,7 @@ export class RegisterController extends BaseController {
|
||||
throw new Error('用户名不能为空');
|
||||
}
|
||||
|
||||
await this.codeService.checkCaptcha(body.captcha);
|
||||
await this.codeService.checkCaptcha(body.captcha,{remoteIp});
|
||||
const newUser = await this.userService.register(body.type, {
|
||||
username: body.username,
|
||||
password: body.password,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ALL, Body, Controller, Inject, Post, Provide, Query } from "@midwayjs/core";
|
||||
import { ALL, Body, Controller, Inject, Post, Provide, Query, RequestIP } from "@midwayjs/core";
|
||||
import {
|
||||
addonRegistry,
|
||||
AddonService,
|
||||
@@ -218,8 +218,8 @@ export class SysSettingsController extends CrudController<SysSettingsService> {
|
||||
|
||||
|
||||
@Post("/captchaTest", { summary: "sys:settings:edit" })
|
||||
async captchaTest(@Body(ALL) body: any) {
|
||||
await this.codeService.checkCaptcha(body)
|
||||
async captchaTest(@Body(ALL) body: any,@RequestIP() remoteIp: string) {
|
||||
await this.codeService.checkCaptcha(body,{remoteIp});
|
||||
return this.ok({});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Inject, Provide, Scope, ScopeEnum } from "@midwayjs/core";
|
||||
import { SysSettingsService } from "@certd/lib-server";
|
||||
import { logger } from "@certd/basic";
|
||||
import { ICaptchaAddon } from "../../../plugins/plugin-captcha/api.js";
|
||||
import { CaptchaRequest, ICaptchaAddon } from "../../../plugins/plugin-captcha/api.js";
|
||||
import { AddonGetterService } from "../../pipeline/service/addon-getter-service.js";
|
||||
|
||||
@Provide()
|
||||
@@ -29,7 +29,7 @@ export class CaptchaService {
|
||||
}
|
||||
|
||||
|
||||
async doValidate(opts: { form: any, must?: boolean, captchaAddonId?: number }) {
|
||||
async doValidate(opts: { form: any, must?: boolean, captchaAddonId?: number,req:CaptchaRequest }) {
|
||||
if (!opts.captchaAddonId) {
|
||||
const settings = await this.sysSettingsService.getPublicSettings();
|
||||
opts.captchaAddonId = settings.captchaAddonId ?? 0;
|
||||
@@ -46,7 +46,7 @@ export class CaptchaService {
|
||||
if (!opts.form) {
|
||||
throw new Error("请输入验证码");
|
||||
}
|
||||
const res = await addon.onValidate(opts.form);
|
||||
const res = await addon.onValidate(opts.form,opts.req);
|
||||
if (!res) {
|
||||
throw new Error("验证码错误");
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { ISmsService } from '../sms/api.js';
|
||||
import { SmsServiceFactory } from '../sms/factory.js';
|
||||
import { CaptchaService } from "./captcha-service.js";
|
||||
import { EmailService } from './email-service.js';
|
||||
import { CaptchaRequest } from '../../../plugins/plugin-captcha/api.js';
|
||||
|
||||
// {data: '<svg.../svg>', text: 'abcd'}
|
||||
/**
|
||||
@@ -25,8 +26,8 @@ export class CodeService {
|
||||
|
||||
|
||||
|
||||
async checkCaptcha(body:any) {
|
||||
return await this.captchaService.doValidate({form:body})
|
||||
async checkCaptcha(body:any,req:CaptchaRequest) {
|
||||
return await this.captchaService.doValidate({form:body,req});
|
||||
}
|
||||
/**
|
||||
*/
|
||||
|
||||
@@ -77,6 +77,13 @@ export class EmailService implements IEmailService {
|
||||
}
|
||||
}
|
||||
let subject = email.subject;
|
||||
|
||||
if (!subject) {
|
||||
logger.error(new Error('邮件标题不能为空'));
|
||||
subject = `邮件标题为空,请联系管理员排查`;
|
||||
}
|
||||
|
||||
|
||||
if (!subject.includes(`【${sysTitle}】`)) {
|
||||
subject = `【${sysTitle}】${subject}`;
|
||||
}
|
||||
@@ -121,7 +128,7 @@ export class EmailService implements IEmailService {
|
||||
data: {
|
||||
title: '测试邮件,from certd',
|
||||
content: '测试邮件,from certd',
|
||||
url:"https://certd.handfree.work",
|
||||
url: "https://certd.handfree.work",
|
||||
},
|
||||
receivers: [receiver],
|
||||
});
|
||||
@@ -150,32 +157,31 @@ export class EmailService implements IEmailService {
|
||||
|
||||
async sendByTemplate(req: EmailSendByTemplateReq) {
|
||||
let content = null
|
||||
if (isPlus()) {
|
||||
const emailConf = await this.sysSettingsService.getSetting<SysEmailConf>(SysEmailConf);
|
||||
const template = emailConf?.templates?.[req.type]
|
||||
if (template && template.addonId) {
|
||||
const addon: ITemplateProvider<EmailContent> = await this.addonGetterService.getAddonById(template.addonId, true, 0)
|
||||
const emailConf = await this.sysSettingsService.getSetting<SysEmailConf>(SysEmailConf);
|
||||
const template = emailConf?.templates?.[req.type]
|
||||
if (isPlus() && template && template.addonId) {
|
||||
const addon: ITemplateProvider<EmailContent> = await this.addonGetterService.getAddonById(template.addonId, true, 0)
|
||||
if (addon) {
|
||||
content = await addon.buildContent({ data: req.data })
|
||||
}
|
||||
}
|
||||
if (isPlus() && !content ) {
|
||||
//看看有没有通用模版
|
||||
if (emailConf?.templates?.common && emailConf?.templates?.common.addonId) {
|
||||
const addon: ITemplateProvider<EmailContent> = await this.addonGetterService.getAddonById(emailConf.templates.common.addonId, true, 0)
|
||||
if (addon) {
|
||||
content = await addon.buildContent({ data: req.data })
|
||||
}
|
||||
}
|
||||
if (!content) {
|
||||
//看看有没有通用模版
|
||||
if (emailConf?.templates?.common && emailConf?.templates?.common.addonId) {
|
||||
const addon: ITemplateProvider<EmailContent> = await this.addonGetterService.getAddonById(emailConf.templates.common.addonId, true, 0)
|
||||
if (addon) {
|
||||
content = await addon.buildContent({ data: req.data })
|
||||
}
|
||||
}
|
||||
}
|
||||
// 没有找到模版,使用默认模版
|
||||
if (!content) {
|
||||
try {
|
||||
const addon: ITemplateProvider<EmailContent> = await this.addonGetterService.getBlank("emailTemplate", req.type)
|
||||
content = await addon.buildDefaultContent({ data: req.data })
|
||||
} catch (e) {
|
||||
// 对应的通知类型模版可能没有注册或者开发
|
||||
}
|
||||
}
|
||||
|
||||
// 没有找到模版,使用默认模版
|
||||
if (!content) {
|
||||
try {
|
||||
const addon: ITemplateProvider<EmailContent> = await this.addonGetterService.getBlank("emailTemplate", req.type)
|
||||
content = await addon.buildDefaultContent({ data: req.data })
|
||||
} catch (e) {
|
||||
// 对应的通知类型模版可能没有注册或者开发
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
import { AliyunAccess } from "../../../plugin-lib/aliyun/access/index.js";
|
||||
import { AliyunSslClient } from "../../../plugin-lib/aliyun/lib/ssl-client.js";
|
||||
import { AliyunClientV2 } from "../../../plugin-lib/aliyun/lib/aliyun-client-v2.js";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
@IsTaskPlugin({
|
||||
name: "AliyunDeployCertToESA",
|
||||
@@ -89,6 +90,19 @@ export class AliyunDeployCertToESA extends AbstractTaskPlugin {
|
||||
)
|
||||
siteIds!: string[];
|
||||
|
||||
@TaskInput({
|
||||
title: "是否免费版",
|
||||
value: true,
|
||||
component: {
|
||||
name: "a-switch",
|
||||
vModel: "value"
|
||||
},
|
||||
helper: "如果是免费站点,将检查证书数量限制,如果超限将删除最旧的那张证书",
|
||||
required: true
|
||||
})
|
||||
|
||||
isFree: boolean;
|
||||
|
||||
|
||||
async onInstance() {
|
||||
}
|
||||
@@ -126,13 +140,9 @@ export class AliyunDeployCertToESA extends AbstractTaskPlugin {
|
||||
const { certId, certName } = await this.getAliyunCertId(access);
|
||||
|
||||
for (const siteId of this.siteIds) {
|
||||
|
||||
try{
|
||||
await this.clearSiteCert(client,siteId);
|
||||
}catch (e) {
|
||||
this.logger.error(`清理站点[${siteId}]证书失败`,e)
|
||||
if (this.isFree) {
|
||||
await this.clearSiteLimitCert(client, siteId);
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await client.doRequest({
|
||||
// 接口名称
|
||||
@@ -140,12 +150,12 @@ export class AliyunDeployCertToESA extends AbstractTaskPlugin {
|
||||
// 接口版本
|
||||
version: "2024-09-10",
|
||||
data: {
|
||||
body:{
|
||||
SiteId: siteId,
|
||||
CasId: certId,
|
||||
Type: "cas",
|
||||
Name: certName
|
||||
}
|
||||
body: {
|
||||
SiteId: siteId,
|
||||
CasId: certId,
|
||||
Type: "cas",
|
||||
Name: certName
|
||||
}
|
||||
}
|
||||
});
|
||||
this.logger.info(`部署站点[${siteId}]证书成功:${JSON.stringify(res)}`);
|
||||
@@ -153,14 +163,14 @@ export class AliyunDeployCertToESA extends AbstractTaskPlugin {
|
||||
} catch (e) {
|
||||
if (e.message.includes("Certificate.Duplicated")) {
|
||||
this.logger.info(`站点[${siteId}]证书已存在,无需重复部署`);
|
||||
}else{
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}finally{
|
||||
try{
|
||||
await this.clearSiteCert(client,siteId);
|
||||
}catch (e) {
|
||||
this.logger.error(`清理站点[${siteId}]证书失败`,e)
|
||||
} finally {
|
||||
try {
|
||||
await this.clearSiteExpiredCert(client, siteId);
|
||||
} catch (e) {
|
||||
this.logger.error(`清理站点[${siteId}]过期证书失败`, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -201,15 +211,16 @@ export class AliyunDeployCertToESA extends AbstractTaskPlugin {
|
||||
return this.ctx.utils.options.buildGroupOptions(options, this.certDomains);
|
||||
}
|
||||
|
||||
async clearSiteCert(client: AliyunClientV2, siteId: string) {
|
||||
async clearSiteExpiredCert(client: AliyunClientV2, siteId: string) {
|
||||
this.logger.info(`开始清理站点[${siteId}]过期证书`);
|
||||
const certListRes = await client.doRequest({
|
||||
action: "ListCertificates",
|
||||
version: "2024-09-10",
|
||||
method: "GET",
|
||||
data:{
|
||||
data: {
|
||||
query: {
|
||||
SiteId: siteId
|
||||
SiteId: siteId,
|
||||
PageSize: 100
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -219,13 +230,13 @@ export class AliyunDeployCertToESA extends AbstractTaskPlugin {
|
||||
this.logger.info(`证书${item.Name}状态:${item.Status}`);
|
||||
if (item.Status === "Expired") {
|
||||
this.logger.info(`证书${item.Name}已过期,执行删除`);
|
||||
try{
|
||||
try {
|
||||
await client.doRequest({
|
||||
action: "DeleteCertificate",
|
||||
version: "2024-09-10",
|
||||
// 接口 HTTP 方法
|
||||
method: "GET",
|
||||
data:{
|
||||
data: {
|
||||
query: {
|
||||
SiteId: siteId,
|
||||
Id: item.id
|
||||
@@ -233,13 +244,76 @@ export class AliyunDeployCertToESA extends AbstractTaskPlugin {
|
||||
}
|
||||
});
|
||||
this.logger.info(`证书${item.Name}已删除`);
|
||||
}catch (e) {
|
||||
this.logger.error(`过期证书${item.Name}删除失败:`,e.message)
|
||||
} catch (e) {
|
||||
this.logger.error(`过期证书${item.Name}删除失败:`, e.message)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async clearSiteLimitCert(client: AliyunClientV2, siteId: string) {
|
||||
const res = await client.doRequest({
|
||||
action: "GetCertificateQuota",
|
||||
version: "2024-09-10",
|
||||
method: "GET",
|
||||
data: {
|
||||
query: {
|
||||
SiteId: siteId,
|
||||
Type: "free"
|
||||
}
|
||||
}
|
||||
});
|
||||
this.logger.info(`站点[${siteId}]证书限制情况, 限制${res.Quota} ,已使用${res.QuotaUsage}`);
|
||||
|
||||
if (res.QuotaUsage < res.Quota) {
|
||||
this.logger.info(`站点[${siteId}]证书未超限制, 无需删除`);
|
||||
return;
|
||||
}
|
||||
//删除最旧的证书
|
||||
this.logger.info(`站点[${siteId}]证书已超限制, 开始删除最旧的证书`);
|
||||
const certListRes = await client.doRequest({
|
||||
action: "ListCertificates",
|
||||
version: "2024-09-10",
|
||||
method: "GET",
|
||||
data: {
|
||||
query: {
|
||||
SiteId: siteId,
|
||||
PageSize: 100
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const list = certListRes.Result;
|
||||
if (!list || list.length === 0) {
|
||||
this.logger.info(`站点[${siteId}]没有证书, 无需删除`);
|
||||
return
|
||||
}
|
||||
let oldly:any = null;
|
||||
for (const item of list) {
|
||||
if (!oldly) {
|
||||
oldly = item;
|
||||
continue;
|
||||
}
|
||||
if (dayjs(item.CreateTime).valueOf() < (dayjs(oldly.CreateTime)).valueOf()){
|
||||
oldly = item;
|
||||
}
|
||||
}
|
||||
this.logger.info(`最旧的证书${oldly.Name}创建时间:${oldly.CreateTime}`);
|
||||
await client.doRequest({
|
||||
action: "DeleteCertificate",
|
||||
version: "2024-09-10",
|
||||
method: "GET",
|
||||
data: {
|
||||
query: {
|
||||
SiteId: siteId,
|
||||
Id: oldly.id
|
||||
}
|
||||
}
|
||||
});
|
||||
this.logger.info(`最旧证书${oldly.Name}已删除`);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
new AliyunDeployCertToESA();
|
||||
|
||||
@@ -11,4 +11,5 @@ export * from './deploy-to-esa/index.js';
|
||||
export * from './deploy-to-vod/index.js';
|
||||
export * from './deploy-to-apigateway/index.js';
|
||||
export * from './deploy-to-apig/index.js';
|
||||
export * from './deploy-to-ack/index.js';
|
||||
export * from './deploy-to-ack/index.js';
|
||||
export * from './deploy-to-all/index.js';
|
||||
@@ -1,4 +1,7 @@
|
||||
export type CaptchaRequest = {
|
||||
remoteIp: string,
|
||||
}
|
||||
export interface ICaptchaAddon{
|
||||
onValidate(data?:any):Promise<any>;
|
||||
onValidate(data?:any,req?:CaptchaRequest):Promise<any>;
|
||||
getCaptcha():Promise<any>;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
import { AddonInput, BaseAddon, IsAddon } from "@certd/lib-server";
|
||||
import { CaptchaRequest, ICaptchaAddon } from "../api.js";
|
||||
|
||||
@IsAddon({
|
||||
addonType: "captcha",
|
||||
name: "cfTurnstile",
|
||||
title: "Cloudflare Turnstile",
|
||||
desc: "谨慎使用,国内被墙了",
|
||||
showTest: false,
|
||||
})
|
||||
export class CfTurnstileCaptcha extends BaseAddon implements ICaptchaAddon {
|
||||
|
||||
@AddonInput({
|
||||
title: "站点密钥",
|
||||
component: {
|
||||
placeholder: "SiteKey",
|
||||
},
|
||||
helper: "[Cloudflare Turnstile](https://www.cloudflare.com/zh-cn/application-services/products/turnstile/) -> 添加小组件",
|
||||
required: true,
|
||||
})
|
||||
siteKey = "";
|
||||
|
||||
@AddonInput({
|
||||
title: "密钥",
|
||||
component: {
|
||||
placeholder: "SecretKey",
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
secretKey = "";
|
||||
|
||||
async onValidate(data?: any, req?: CaptchaRequest) {
|
||||
if (!data) {
|
||||
return false;
|
||||
}
|
||||
const { token } = data;
|
||||
const { remoteIp } = req;
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('secret', this.secretKey);
|
||||
formData.append('response', token);
|
||||
formData.append('remoteip', remoteIp);
|
||||
|
||||
const res = await this.http.request({
|
||||
url: 'https://challenges.cloudflare.com/turnstile/v0/siteverify',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
data: formData
|
||||
})
|
||||
|
||||
if (res.success) {
|
||||
// Token is valid - process the form
|
||||
return true;
|
||||
} else {
|
||||
// Token is invalid - reject the submission
|
||||
const errorMessage = 'Cloudflare Turnstile 校验失败:' + res['error-codes'].join(', ')
|
||||
this.logger.error(errorMessage);
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
async getCaptcha(): Promise<any> {
|
||||
return {
|
||||
siteKey: this.siteKey,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './geetest/index.js';
|
||||
export * from './image/index.js';
|
||||
export * from './tencent/index.js';
|
||||
export * from './cf-turnstile/index.js';
|
||||
@@ -1,3 +1,4 @@
|
||||
import { resetLogConfigure } from '@certd/basic';
|
||||
import { IsAccess, AccessInput, BaseAccess } from '@certd/pipeline';
|
||||
|
||||
@IsAccess({
|
||||
@@ -26,6 +27,26 @@ export class HuaweiAccess extends BaseAccess {
|
||||
encrypt: true,
|
||||
})
|
||||
accessKeySecret = '';
|
||||
|
||||
|
||||
async getProjectList() {
|
||||
const endpoint = "https://iam.cn-north-4.myhuaweicloud.com";
|
||||
|
||||
const { BasicCredentials } = await import('@huaweicloud/huaweicloud-sdk-core');
|
||||
const iam = await import('@huaweicloud/huaweicloud-sdk-iam/v3/public-api.js');
|
||||
//恢复华为云把log4j的config改了的问题
|
||||
resetLogConfigure();
|
||||
const credentials: any = new BasicCredentials().withAk(this.accessKeyId).withSk(this.accessKeySecret)
|
||||
|
||||
|
||||
const client = iam.IamClient.newBuilder()
|
||||
.withCredential(credentials)
|
||||
.withEndpoint(endpoint)
|
||||
.build();
|
||||
const request = new iam.KeystoneListAuthProjectsRequest();
|
||||
const result = await client.keystoneListAuthProjects(request);
|
||||
return result.projects;
|
||||
}
|
||||
}
|
||||
|
||||
new HuaweiAccess();
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, PageSearch, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||
import { HuaweiAccess } from '../../access/index.js';
|
||||
import { CertInfo } from '@certd/plugin-cert';
|
||||
import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib';
|
||||
import { resetLogConfigure } from '@certd/basic';
|
||||
import { CertApplyPluginNames } from '@certd/plugin-cert';
|
||||
@IsTaskPlugin({
|
||||
name: 'HauweiDeployCertToELB',
|
||||
title: '华为云-部署证书至ELB负载均衡',
|
||||
icon: 'svg:icon-huawei',
|
||||
group: pluginGroups.huawei.key,
|
||||
desc: '',
|
||||
default: {
|
||||
strategy: {
|
||||
runStrategy: RunStrategy.SkipWhenSucceed,
|
||||
},
|
||||
},
|
||||
})
|
||||
export class HauweiDeployCertToELB extends AbstractTaskPlugin {
|
||||
@TaskInput({
|
||||
title: '域名证书',
|
||||
helper: '请选择前置任务输出的域名证书\n如果你选择使用ccm证书ID,则需要在[域名管理页面右上角开启SCM授权](https://console.huaweicloud.com/cdn/#/cdn/domain)',
|
||||
component: {
|
||||
name: 'output-selector',
|
||||
from: [...CertApplyPluginNames],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
cert!: CertInfo;
|
||||
|
||||
@TaskInput(createCertDomainGetterInputDefine({ props: { required: false } }))
|
||||
certDomains!: string[];
|
||||
|
||||
|
||||
@TaskInput({
|
||||
title: 'Access授权',
|
||||
helper: '华为云授权AccessKeyId、AccessKeySecret',
|
||||
component: {
|
||||
name: 'access-selector',
|
||||
type: 'huawei',
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
accessId!: string;
|
||||
|
||||
@TaskInput(
|
||||
createRemoteSelectInputDefine({
|
||||
title: '项目ID',
|
||||
helper: '请选择项目',
|
||||
typeName: 'HauweiDeployCertToELB',
|
||||
action: HauweiDeployCertToELB.prototype.onGetProjectList.name,
|
||||
multi:false
|
||||
})
|
||||
)
|
||||
projectId!: string;
|
||||
|
||||
@TaskInput(
|
||||
createRemoteSelectInputDefine({
|
||||
title: 'ELB已有证书',
|
||||
helper: '请选择域名或输入域名',
|
||||
typeName: 'HauweiDeployCertToELB',
|
||||
action: HauweiDeployCertToELB.prototype.onGetCertList.name,
|
||||
search: true,
|
||||
})
|
||||
)
|
||||
certIds!: string[];
|
||||
|
||||
|
||||
|
||||
async execute(): Promise<void> {
|
||||
if (!this.cert) {
|
||||
throw new Error('域名证书不能为空');
|
||||
}
|
||||
this.logger.info('开始部署证书到华为云ELB');
|
||||
const { elb, client } = await this.getElbClient();
|
||||
|
||||
for (const certId of this.certIds) {
|
||||
this.logger.info('开始更新ELB证书,证书ID:' + certId);
|
||||
let request = new elb.UpdateCertificateRequest(certId);
|
||||
|
||||
const certificate = new elb.UpdateCertificateOption()
|
||||
.withCertificate(this.cert.crt)
|
||||
.withPrivateKey(this.cert.key);
|
||||
const body = new elb.UpdateCertificateRequestBody()
|
||||
.withCertificate(certificate);
|
||||
request.withBody(body);
|
||||
|
||||
await client.updateCertificate(request);
|
||||
this.logger.info('更新ELB证书完成,证书ID:' + certId );
|
||||
await this.ctx.utils.sleep(2000);
|
||||
}
|
||||
|
||||
this.logger.info('更新ELB证书完成');
|
||||
}
|
||||
|
||||
async onGetProjectList() {
|
||||
const access = await this.getAccess<HuaweiAccess>(this.accessId);
|
||||
const projects = await access.getProjectList();
|
||||
return projects.map(project => {
|
||||
return {
|
||||
value: project.id+"_"+project.name,
|
||||
label: `${project.name}(${project.id})`,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async getElbClient() {
|
||||
if (!this.projectId) {
|
||||
throw new Error('项目ID不能为空');
|
||||
}
|
||||
const access = await this.getAccess<HuaweiAccess>(this.accessId);
|
||||
const { BasicCredentials } = await import('@huaweicloud/huaweicloud-sdk-core');
|
||||
const elb = await import('@huaweicloud/huaweicloud-sdk-elb/v3/public-api.js');
|
||||
//恢复华为云把log4j的config改了的问题
|
||||
resetLogConfigure();
|
||||
const projectArr = this.projectId.split("_");
|
||||
const projectId = projectArr[0];
|
||||
const region = projectArr[1];
|
||||
const credentials: any = new BasicCredentials().withAk(access.accessKeyId).withSk(access.accessKeySecret).withProjectId(projectId);
|
||||
const client = elb.ElbClient.newBuilder().withCredential(credentials).withEndpoint('https://elb.'+region+'.myhuaweicloud.com').build();
|
||||
return {
|
||||
client,
|
||||
elb,
|
||||
};
|
||||
}
|
||||
async onGetCertList(data: PageSearch) {
|
||||
const { client, elb } = await this.getElbClient();
|
||||
|
||||
const request = new elb.ListCertificatesRequest();
|
||||
request.limit = 1000;
|
||||
if (data.searchKey) {
|
||||
request.withDomain([data.searchKey]);
|
||||
}
|
||||
const result = await client.listCertificates(request);
|
||||
if (!result || !result.certificates || result.certificates.length === 0) {
|
||||
throw new Error('未找到ELB证书,您可以手动输入');
|
||||
}
|
||||
|
||||
const certs = result.certificates.map(cert => {
|
||||
return {
|
||||
value: cert.id,
|
||||
//@ts-ignore
|
||||
label: cert.id + '(' + cert.common_name + ')',
|
||||
domain: cert.domain.split(','),
|
||||
};
|
||||
});
|
||||
|
||||
return this.ctx.utils.options.buildGroupOptions(certs, this.certDomains);
|
||||
}
|
||||
}
|
||||
new HauweiDeployCertToELB();
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './deploy-to-cdn/index.js'
|
||||
export * from './upload-to-ccm/index.js'
|
||||
export * from './deploy-to-obs/index.js'
|
||||
export * from './deploy-to-elb/index.js'
|
||||
|
||||
+1
-1
@@ -136,7 +136,7 @@ export class LeCDNUpdateCertV2 extends AbstractTaskPlugin {
|
||||
|
||||
private checkRes(res: any) {
|
||||
if (res.code !== 0 && res.code !== 200) {
|
||||
throw new Error(res.message);
|
||||
throw new Error(res.message || JSON.stringify(res));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Generated
+81
-55
@@ -49,7 +49,7 @@ importers:
|
||||
packages/core/acme-client:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../basic
|
||||
'@peculiar/x509':
|
||||
specifier: ^1.11.0
|
||||
@@ -213,10 +213,10 @@ importers:
|
||||
packages/core/pipeline:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../basic
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../pro/plus-core
|
||||
dayjs:
|
||||
specifier: ^1.11.7
|
||||
@@ -412,7 +412,7 @@ importers:
|
||||
packages/libs/lib-k8s:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../core/basic
|
||||
'@kubernetes/client-node':
|
||||
specifier: 0.21.0
|
||||
@@ -452,19 +452,19 @@ importers:
|
||||
packages/libs/lib-server:
|
||||
dependencies:
|
||||
'@certd/acme-client':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../core/acme-client
|
||||
'@certd/basic':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../core/basic
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plugin-lib':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../plugins/plugin-lib
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../pro/plus-core
|
||||
'@midwayjs/cache':
|
||||
specifier: 3.14.0
|
||||
@@ -610,16 +610,16 @@ importers:
|
||||
packages/plugins/plugin-cert:
|
||||
dependencies:
|
||||
'@certd/acme-client':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../core/acme-client
|
||||
'@certd/basic':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../core/basic
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plugin-lib':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../plugin-lib
|
||||
psl:
|
||||
specifier: ^1.9.0
|
||||
@@ -683,16 +683,16 @@ importers:
|
||||
specifier: ^3.964.0
|
||||
version: 3.964.0(aws-crt@1.26.2)
|
||||
'@certd/acme-client':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../core/acme-client
|
||||
'@certd/basic':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../core/basic
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../pro/plus-core
|
||||
'@kubernetes/client-node':
|
||||
specifier: 0.21.0
|
||||
@@ -783,16 +783,16 @@ importers:
|
||||
packages/pro/commercial-core:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../core/basic
|
||||
'@certd/lib-server':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../libs/lib-server
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../plus-core
|
||||
'@midwayjs/core':
|
||||
specifier: 3.20.11
|
||||
@@ -865,16 +865,16 @@ importers:
|
||||
packages/pro/plugin-plus:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../core/basic
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plugin-lib':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../plugins/plugin-lib
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../plus-core
|
||||
crypto-js:
|
||||
specifier: ^4.2.0
|
||||
@@ -950,7 +950,7 @@ importers:
|
||||
packages/pro/plus-core:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../core/basic
|
||||
dayjs:
|
||||
specifier: ^1.11.7
|
||||
@@ -1246,10 +1246,10 @@ importers:
|
||||
version: 0.1.3(zod@3.24.4)
|
||||
devDependencies:
|
||||
'@certd/lib-iframe':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../libs/lib-iframe
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../core/pipeline
|
||||
'@rollup/plugin-commonjs':
|
||||
specifier: ^25.0.7
|
||||
@@ -1438,56 +1438,62 @@ importers:
|
||||
specifier: ^3.964.0
|
||||
version: 3.964.0(aws-crt@1.26.2)
|
||||
'@certd/acme-client':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../core/acme-client
|
||||
'@certd/basic':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../core/basic
|
||||
'@certd/commercial-core':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../pro/commercial-core
|
||||
'@certd/cv4pve-api-javascript':
|
||||
specifier: ^8.4.2
|
||||
version: 8.4.2
|
||||
'@certd/jdcloud':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../libs/lib-jdcloud
|
||||
'@certd/lib-huawei':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../libs/lib-huawei
|
||||
'@certd/lib-k8s':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../libs/lib-k8s
|
||||
'@certd/lib-server':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../libs/lib-server
|
||||
'@certd/midway-flyway-js':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../libs/midway-flyway-js
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plugin-cert':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../plugins/plugin-cert
|
||||
'@certd/plugin-lib':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../plugins/plugin-lib
|
||||
'@certd/plugin-plus':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../pro/plugin-plus
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.38.1
|
||||
specifier: ^1.38.3
|
||||
version: link:../../pro/plus-core
|
||||
'@google-cloud/publicca':
|
||||
specifier: ^1.3.0
|
||||
version: 1.3.0(encoding@0.1.13)
|
||||
'@huaweicloud/huaweicloud-sdk-cdn':
|
||||
specifier: ^3.1.120
|
||||
version: 3.1.149
|
||||
specifier: ^3.1.185
|
||||
version: 3.1.185
|
||||
'@huaweicloud/huaweicloud-sdk-core':
|
||||
specifier: ^3.1.120
|
||||
version: 3.1.149
|
||||
specifier: ^3.1.185
|
||||
version: 3.1.185
|
||||
'@huaweicloud/huaweicloud-sdk-elb':
|
||||
specifier: ^3.1.185
|
||||
version: 3.1.185
|
||||
'@huaweicloud/huaweicloud-sdk-iam':
|
||||
specifier: ^3.1.185
|
||||
version: 3.1.185
|
||||
'@koa/cors':
|
||||
specifier: ^5.0.0
|
||||
version: 5.0.0
|
||||
@@ -3407,11 +3413,17 @@ packages:
|
||||
'@httptoolkit/websocket-stream@6.0.1':
|
||||
resolution: {integrity: sha512-A0NOZI+Glp3Xgcz6Na7i7o09+/+xm2m0UCU8gdtM2nIv6/cjLmhMZMqehSpTlgbx9omtLmV8LVqOskPEyWnmZQ==}
|
||||
|
||||
'@huaweicloud/huaweicloud-sdk-cdn@3.1.149':
|
||||
resolution: {integrity: sha512-orvtJRgJA/KKCmu6jLKxjMLhdxuKEOyeAakQCi3kwgWcbbeQUbRbr+2iMKLqXdM4lCrbOlfe06uqEtC/AG9ZRA==}
|
||||
'@huaweicloud/huaweicloud-sdk-cdn@3.1.185':
|
||||
resolution: {integrity: sha512-n4X0TDXpBFUbLFNkHbHbADETT4CG1Z8GgxDyQQrZHVMR3cUS2FnB8IJV1h34MToIB2D68u9ftOBrIjpnfgxIcg==}
|
||||
|
||||
'@huaweicloud/huaweicloud-sdk-core@3.1.149':
|
||||
resolution: {integrity: sha512-5fY87f/z46L4jzB6YPpc3Qq6gt49C4J0//0AV7ELuOfmtstzbuS0O5UmBuTurTtAtsbPgW+08jn42N8Aqa2gGw==}
|
||||
'@huaweicloud/huaweicloud-sdk-core@3.1.185':
|
||||
resolution: {integrity: sha512-gSrJ5lFR0mqm5lQxTpSJ+ZIQTI5fzmM7a80ot4zvZ5Ll8T4HfcpcvEgDb/Q6VyZfPEApHo70CsreUe4PHGe8jQ==}
|
||||
|
||||
'@huaweicloud/huaweicloud-sdk-elb@3.1.185':
|
||||
resolution: {integrity: sha512-GKtB/cntti5coam7WBgjhNPzhpr9WdZz5EB2NZO5mFtdQ106ztQa8uIxt04PumFC71nQaC0LbAlAK7JrHVGjrw==}
|
||||
|
||||
'@huaweicloud/huaweicloud-sdk-iam@3.1.185':
|
||||
resolution: {integrity: sha512-uZFsGyFCVYET5RxBW6nwM53ooKmggdkZAOFu8ZHvuVl3chOxPAt35jrEpznvUk7iApIn5XSC62t4DAKIslPFcg==}
|
||||
|
||||
'@humanwhocodes/config-array@0.11.14':
|
||||
resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==}
|
||||
@@ -15137,14 +15149,14 @@ snapshots:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
|
||||
'@huaweicloud/huaweicloud-sdk-cdn@3.1.149':
|
||||
'@huaweicloud/huaweicloud-sdk-cdn@3.1.185':
|
||||
dependencies:
|
||||
'@huaweicloud/huaweicloud-sdk-core': 3.1.149
|
||||
'@huaweicloud/huaweicloud-sdk-core': 3.1.185
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
- supports-color
|
||||
|
||||
'@huaweicloud/huaweicloud-sdk-core@3.1.149':
|
||||
'@huaweicloud/huaweicloud-sdk-core@3.1.185':
|
||||
dependencies:
|
||||
axios: 1.9.0(debug@4.4.3)
|
||||
form-data: 4.0.2
|
||||
@@ -15159,6 +15171,20 @@ snapshots:
|
||||
- debug
|
||||
- supports-color
|
||||
|
||||
'@huaweicloud/huaweicloud-sdk-elb@3.1.185':
|
||||
dependencies:
|
||||
'@huaweicloud/huaweicloud-sdk-core': 3.1.185
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
- supports-color
|
||||
|
||||
'@huaweicloud/huaweicloud-sdk-iam@3.1.185':
|
||||
dependencies:
|
||||
'@huaweicloud/huaweicloud-sdk-core': 3.1.185
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
- supports-color
|
||||
|
||||
'@humanwhocodes/config-array@0.11.14':
|
||||
dependencies:
|
||||
'@humanwhocodes/object-schema': 2.0.3
|
||||
@@ -19945,13 +19971,13 @@ snapshots:
|
||||
resolve: 1.22.10
|
||||
semver: 6.3.1
|
||||
|
||||
eslint-plugin-prettier@3.4.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@7.32.0)(prettier@2.8.8):
|
||||
eslint-plugin-prettier@3.4.1(eslint-config-prettier@8.10.0(eslint@7.32.0))(eslint@7.32.0)(prettier@2.8.8):
|
||||
dependencies:
|
||||
eslint: 7.32.0
|
||||
prettier: 2.8.8
|
||||
prettier-linter-helpers: 1.0.0
|
||||
optionalDependencies:
|
||||
eslint-config-prettier: 8.10.0(eslint@8.57.0)
|
||||
eslint-config-prettier: 8.10.0(eslint@7.32.0)
|
||||
|
||||
eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8):
|
||||
dependencies:
|
||||
@@ -22351,7 +22377,7 @@ snapshots:
|
||||
eslint: 7.32.0
|
||||
eslint-config-prettier: 8.10.0(eslint@7.32.0)
|
||||
eslint-plugin-node: 11.1.0(eslint@7.32.0)
|
||||
eslint-plugin-prettier: 3.4.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@7.32.0)(prettier@2.8.8)
|
||||
eslint-plugin-prettier: 3.4.1(eslint-config-prettier@8.10.0(eslint@7.32.0))(eslint@7.32.0)(prettier@2.8.8)
|
||||
execa: 5.1.1
|
||||
inquirer: 7.3.3
|
||||
json5: 2.2.3
|
||||
|
||||
@@ -1 +1 @@
|
||||
12:32
|
||||
01:02
|
||||
|
||||
@@ -1 +1 @@
|
||||
13:11
|
||||
01:17
|
||||
|
||||
Reference in New Issue
Block a user