mirror of
https://github.com/certd/certd.git
synced 2026-04-24 12:27:25 +08:00
perf: 支持设置默认的证书申请地址的反向代理
This commit is contained in:
@@ -57,6 +57,32 @@ export function getDirectoryUrl(opts) {
|
|||||||
return list.production
|
return list.production
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function getAllSslProviderDomains() {
|
||||||
|
const list = Object.values(directory).map((item) => {
|
||||||
|
let url = item.production.replace('https://', '')
|
||||||
|
url = url.substring(0, url.indexOf('/'))
|
||||||
|
return url
|
||||||
|
})
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
let sslProviderReverseProxies = {}
|
||||||
|
|
||||||
|
function initSslProviderReverseProxies() {
|
||||||
|
for (const sslProvider of getAllSslProviderDomains()) {
|
||||||
|
sslProviderReverseProxies[sslProvider] = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
initSslProviderReverseProxies()
|
||||||
|
|
||||||
|
export function getSslProviderReverseProxies() {
|
||||||
|
return sslProviderReverseProxies
|
||||||
|
}
|
||||||
|
export function setSslProviderReverseProxies(reverseProxies) {
|
||||||
|
Object.assign(sslProviderReverseProxies, reverseProxies)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Crypto
|
* Crypto
|
||||||
*/
|
*/
|
||||||
|
|||||||
+3
@@ -118,6 +118,9 @@ export const directory: {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function getDirectoryUrl(opts:{sslProvider:string, pkType: string}): string;
|
export function getDirectoryUrl(opts:{sslProvider:string, pkType: string}): string;
|
||||||
|
export function getAllSslProviderDomains(): string[];
|
||||||
|
export function getSslProviderReverseProxies(): Record<string, string>;
|
||||||
|
export function setSslProviderReverseProxies(reverseProxies: Record<string, string>): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Crypto
|
* Crypto
|
||||||
|
|||||||
@@ -76,6 +76,9 @@ export class SysPrivateSettings extends BaseSettings {
|
|||||||
|
|
||||||
httpsProxy? = '';
|
httpsProxy? = '';
|
||||||
httpProxy? = '';
|
httpProxy? = '';
|
||||||
|
|
||||||
|
reverseProxies?: Record<string, string> = {};
|
||||||
|
|
||||||
dnsResultOrder? = '';
|
dnsResultOrder? = '';
|
||||||
commonCnameEnabled?: boolean = true;
|
commonCnameEnabled?: boolean = true;
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import { Repository } from 'typeorm';
|
|||||||
import { SysSettingsEntity } from '../entity/sys-settings.js';
|
import { SysSettingsEntity } from '../entity/sys-settings.js';
|
||||||
import { BaseSettings, SysInstallInfo, SysPrivateSettings, SysPublicSettings, SysSecret, SysSecretBackup } from './models.js';
|
import { BaseSettings, SysInstallInfo, SysPrivateSettings, SysPublicSettings, SysSecret, SysSecretBackup } from './models.js';
|
||||||
|
|
||||||
import { BaseService } from '../../../basic/index.js';
|
import { getAllSslProviderDomains, setSslProviderReverseProxies } from '@certd/acme-client';
|
||||||
import { cache, logger, setGlobalProxy } from '@certd/basic';
|
import { cache, logger, mergeUtils, setGlobalProxy } from '@certd/basic';
|
||||||
import * as dns from 'node:dns';
|
import * as dns from 'node:dns';
|
||||||
import {mergeUtils} from "@certd/basic";
|
import { BaseService } from '../../../basic/index.js';
|
||||||
import { executorQueue } from '../../basic/service/executor-queue.js';
|
import { executorQueue } from '../../basic/service/executor-queue.js';
|
||||||
const {merge} = mergeUtils;
|
const {merge} = mergeUtils;
|
||||||
/**
|
/**
|
||||||
@@ -120,7 +120,14 @@ export class SysSettingsService extends BaseService<SysSettingsEntity> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getPrivateSettings(): Promise<SysPrivateSettings> {
|
async getPrivateSettings(): Promise<SysPrivateSettings> {
|
||||||
return await this.getSetting(SysPrivateSettings);
|
const res = await this.getSetting<SysPrivateSettings>(SysPrivateSettings);
|
||||||
|
const sslProviderDomains = getAllSslProviderDomains();
|
||||||
|
for (const domain of sslProviderDomains) {
|
||||||
|
if (!res.reverseProxies[domain]) {
|
||||||
|
res.reverseProxies[domain] = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
async savePrivateSettings(bean: SysPrivateSettings) {
|
async savePrivateSettings(bean: SysPrivateSettings) {
|
||||||
@@ -145,6 +152,8 @@ export class SysSettingsService extends BaseService<SysSettingsEntity> {
|
|||||||
if (bean.pipelineMaxRunningCount){
|
if (bean.pipelineMaxRunningCount){
|
||||||
executorQueue.setMaxRunningCount(bean.pipelineMaxRunningCount);
|
executorQueue.setMaxRunningCount(bean.pipelineMaxRunningCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setSslProviderReverseProxies(bean.reverseProxies);
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateByKey(key: string, setting: any) {
|
async updateByKey(key: string, setting: any) {
|
||||||
|
|||||||
@@ -785,6 +785,7 @@ export default {
|
|||||||
captchaSetting: "Captcha Setting",
|
captchaSetting: "Captcha Setting",
|
||||||
pipelineSetting: "Pipeline Settings",
|
pipelineSetting: "Pipeline Settings",
|
||||||
oauthSetting: "OAuth2 Settings",
|
oauthSetting: "OAuth2 Settings",
|
||||||
|
networkSetting: "Network Settings",
|
||||||
|
|
||||||
showRunStrategy: "Show RunStrategy",
|
showRunStrategy: "Show RunStrategy",
|
||||||
showRunStrategyHelper: "Allow modify the run strategy of the task",
|
showRunStrategyHelper: "Allow modify the run strategy of the task",
|
||||||
@@ -836,6 +837,11 @@ export default {
|
|||||||
notice: "System Notice",
|
notice: "System Notice",
|
||||||
noticeHelper: "System notice, will be displayed on the login page",
|
noticeHelper: "System notice, will be displayed on the login page",
|
||||||
noticePlaceholder: "System notice",
|
noticePlaceholder: "System notice",
|
||||||
|
|
||||||
|
reverseProxy: "Reverse Proxy List",
|
||||||
|
reverseProxyHelper: "Reverse proxy for ACME address, used when applying for certificate",
|
||||||
|
reverseProxyPlaceholder: "http://le.px.handfree.work",
|
||||||
|
reverseProxyEmpty: "No reverse proxy list configured",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
modal: {
|
modal: {
|
||||||
|
|||||||
@@ -792,6 +792,7 @@ export default {
|
|||||||
captchaSetting: "验证码设置",
|
captchaSetting: "验证码设置",
|
||||||
pipelineSetting: "流水线设置",
|
pipelineSetting: "流水线设置",
|
||||||
oauthSetting: "第三方登录",
|
oauthSetting: "第三方登录",
|
||||||
|
networkSetting: "网络设置",
|
||||||
|
|
||||||
showRunStrategy: "显示运行策略选择",
|
showRunStrategy: "显示运行策略选择",
|
||||||
showRunStrategyHelper: "任务设置中是否允许选择运行策略",
|
showRunStrategyHelper: "任务设置中是否允许选择运行策略",
|
||||||
@@ -851,6 +852,11 @@ export default {
|
|||||||
notice: "系统公告",
|
notice: "系统公告",
|
||||||
noticeHelper: "系统公告,将在首页显示",
|
noticeHelper: "系统公告,将在首页显示",
|
||||||
noticePlaceholder: "系统公告",
|
noticePlaceholder: "系统公告",
|
||||||
|
|
||||||
|
reverseProxy: "反向代理列表",
|
||||||
|
reverseProxyHelper: "证书颁发机构ACME地址的反向代理,在申请证书时自动使用",
|
||||||
|
reverseProxyPlaceholder: "http://le.px.handfree.work",
|
||||||
|
reverseProxyEmpty: "未配置反向代理",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
modal: {
|
modal: {
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ export type SuiteSetting = {
|
|||||||
export type SysPrivateSetting = {
|
export type SysPrivateSetting = {
|
||||||
httpProxy?: string;
|
httpProxy?: string;
|
||||||
httpsProxy?: string;
|
httpsProxy?: string;
|
||||||
|
reverseProxies?: any;
|
||||||
dnsResultOrder?: string;
|
dnsResultOrder?: string;
|
||||||
commonCnameEnabled?: boolean;
|
commonCnameEnabled?: boolean;
|
||||||
// 同一个用户同时最大运行流水线数量
|
// 同一个用户同时最大运行流水线数量
|
||||||
|
|||||||
@@ -372,6 +372,13 @@ h6 {
|
|||||||
border-spacing: 0;
|
border-spacing: 0;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
||||||
|
&.cd-table-none-border {
|
||||||
|
border: 0 !important;
|
||||||
|
td, th {
|
||||||
|
border: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.fs-loading {
|
.fs-loading {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
|||||||
@@ -1065,7 +1065,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
.layout-right {
|
.layout-right {
|
||||||
width: 364px;
|
width: 368px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
max-width: 90vw;
|
max-width: 90vw;
|
||||||
}
|
}
|
||||||
@@ -1292,7 +1292,7 @@ export default defineComponent({
|
|||||||
.layout-right {
|
.layout-right {
|
||||||
position: relative;
|
position: relative;
|
||||||
&.collapsed {
|
&.collapsed {
|
||||||
margin-right: max(-364px, -90vw);
|
margin-right: max(-368px, -90vw);
|
||||||
}
|
}
|
||||||
|
|
||||||
.collapse-toggle {
|
.collapse-toggle {
|
||||||
|
|||||||
@@ -26,6 +26,9 @@
|
|||||||
<a-tab-pane key="pipeline" :tab="t('certd.sys.setting.pipelineSetting')">
|
<a-tab-pane key="pipeline" :tab="t('certd.sys.setting.pipelineSetting')">
|
||||||
<SettingPipeline v-if="activeKey === 'pipeline'" />
|
<SettingPipeline v-if="activeKey === 'pipeline'" />
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
|
<a-tab-pane key="network" :tab="t('certd.sys.setting.networkSetting')">
|
||||||
|
<SettingNetwork v-if="activeKey === 'network'" />
|
||||||
|
</a-tab-pane>
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
</div>
|
</div>
|
||||||
</fs-page>
|
</fs-page>
|
||||||
@@ -39,6 +42,7 @@ import SettingSafe from "/@/views/sys/settings/tabs/safe.vue";
|
|||||||
import SettingCaptcha from "/@/views/sys/settings/tabs/captcha.vue";
|
import SettingCaptcha from "/@/views/sys/settings/tabs/captcha.vue";
|
||||||
import SettingPipeline from "/@/views/sys/settings/tabs/pipeline.vue";
|
import SettingPipeline from "/@/views/sys/settings/tabs/pipeline.vue";
|
||||||
import SettingOauth from "/@/views/sys/settings/tabs/oauth.vue";
|
import SettingOauth from "/@/views/sys/settings/tabs/oauth.vue";
|
||||||
|
import SettingNetwork from "/@/views/sys/settings/tabs/network.vue";
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { useSettingStore } from "/@/store/settings";
|
import { useSettingStore } from "/@/store/settings";
|
||||||
|
|||||||
@@ -15,33 +15,6 @@
|
|||||||
<a-switch v-model:checked="formState.public.robots" />
|
<a-switch v-model:checked="formState.public.robots" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
<a-form-item :label="t('certd.httpProxy')" :name="['private', 'httpProxy']" :rules="urlRules">
|
|
||||||
<a-input v-model:value="formState.private.httpProxy" :placeholder="t('certd.httpProxyPlaceholder')" />
|
|
||||||
<div class="helper">{{ t("certd.httpProxyHelper") }}</div>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item :label="t('certd.httpsProxy')" :name="['private', 'httpsProxy']" :rules="urlRules">
|
|
||||||
<div class="flex">
|
|
||||||
<a-input v-model:value="formState.private.httpsProxy" :placeholder="t('certd.httpsProxyPlaceholder')" />
|
|
||||||
<a-button class="ml-5" type="primary" :loading="testProxyLoading" :title="t('certd.saveThenTestTitle')" @click="testProxy">{{ t("certd.testButton") }}</a-button>
|
|
||||||
</div>
|
|
||||||
<div class="helper">{{ t("certd.httpsProxyHelper") }}</div>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item :label="t('certd.dualStackNetwork')" :name="['private', 'dnsResultOrder']">
|
|
||||||
<a-select v-model:value="formState.private.dnsResultOrder">
|
|
||||||
<a-select-option value="verbatim">{{ t("certd.default") }}</a-select-option>
|
|
||||||
<a-select-option value="ipv4first">{{ t("certd.ipv4Priority") }}</a-select-option>
|
|
||||||
<a-select-option value="ipv6first">{{ t("certd.ipv6Priority") }}</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
<div class="helper">{{ t("certd.dualStackNetworkHelper") }}, <a href="https://certd.docmirror.cn/guide/use/setting/ipv6.html" target="_blank">{{ t("certd.helpDocLink") }}</a></div>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item :label="t('certd.sys.setting.showRunStrategy')" :name="['public', 'showRunStrategy']">
|
|
||||||
<a-switch v-model:checked="formState.public.showRunStrategy" />
|
|
||||||
<div class="helper">{{ t("certd.sys.setting.showRunStrategyHelper") }}</div>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item :label="t('certd.enableCommonCnameService')" :name="['private', 'commonCnameEnabled']">
|
<a-form-item :label="t('certd.enableCommonCnameService')" :name="['private', 'commonCnameEnabled']">
|
||||||
<a-switch v-model:checked="formState.private.commonCnameEnabled" />
|
<a-switch v-model:checked="formState.private.commonCnameEnabled" />
|
||||||
<div class="helper" v-html="t('certd.commonCnameHelper')"></div>
|
<div class="helper" v-html="t('certd.commonCnameHelper')"></div>
|
||||||
@@ -60,16 +33,14 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="tsx">
|
<script setup lang="tsx">
|
||||||
import { reactive, ref } from "vue";
|
|
||||||
import { SysSettings } from "/@/views/sys/settings/api";
|
|
||||||
import * as api from "/@/views/sys/settings/api";
|
|
||||||
import { merge } from "lodash-es";
|
|
||||||
import { useSettingStore } from "/@/store/settings";
|
|
||||||
import { notification } from "ant-design-vue";
|
import { notification } from "ant-design-vue";
|
||||||
import { util } from "/@/utils";
|
import { merge } from "lodash-es";
|
||||||
|
import { reactive, ref } from "vue";
|
||||||
|
import { useSettingStore } from "/@/store/settings";
|
||||||
|
import * as api from "/@/views/sys/settings/api";
|
||||||
|
import { SysSettings } from "/@/views/sys/settings/api";
|
||||||
|
|
||||||
import { useI18n } from "/src/locales";
|
import { useI18n } from "/src/locales";
|
||||||
import AddonSelector from "../../../certd/addon/addon-selector/index.vue";
|
|
||||||
import CaptchaInput from "/@/components/captcha/captcha-input.vue";
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
@@ -84,11 +55,6 @@ const formState = reactive<Partial<SysSettings>>({
|
|||||||
private: {},
|
private: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
const urlRules = ref({
|
|
||||||
type: "url",
|
|
||||||
message: "请输入正确的URL",
|
|
||||||
});
|
|
||||||
|
|
||||||
async function loadSysSettings() {
|
async function loadSysSettings() {
|
||||||
const data: any = await api.SysSettingsGet();
|
const data: any = await api.SysSettingsGet();
|
||||||
merge(formState, data);
|
merge(formState, data);
|
||||||
@@ -110,43 +76,6 @@ const onFinish = async (form: any) => {
|
|||||||
saveLoading.value = false;
|
saveLoading.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const testProxyLoading = ref(false);
|
|
||||||
async function testProxy() {
|
|
||||||
testProxyLoading.value = true;
|
|
||||||
try {
|
|
||||||
const res = await api.TestProxy();
|
|
||||||
let success = true;
|
|
||||||
if (res.google !== true || res.baidu !== true) {
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
const content = () => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
{t("certd.google")}: {res.google === true ? t("certd.success") : util.maxLength(res.google)}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{t("certd.baidu")}: {res.baidu === true ? t("certd.success") : util.maxLength(res.baidu)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
if (!success) {
|
|
||||||
notification.error({
|
|
||||||
message: t("certd.testFailed"),
|
|
||||||
description: content,
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
notification.success({
|
|
||||||
message: t("certd.testCompleted"),
|
|
||||||
description: content,
|
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
testProxyLoading.value = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
.sys-settings-base {
|
.sys-settings-base {
|
||||||
|
|||||||
@@ -0,0 +1,127 @@
|
|||||||
|
<template>
|
||||||
|
<div class="sys-settings-form sys-settings-network">
|
||||||
|
<a-form :model="formState" name="basic" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }" autocomplete="off" @finish="onFinish">
|
||||||
|
<a-form-item :label="t('certd.httpProxy')" :name="['private', 'httpProxy']" :rules="urlRules">
|
||||||
|
<a-input v-model:value="formState.private.httpProxy" :placeholder="t('certd.httpProxyPlaceholder')" />
|
||||||
|
<div class="helper">{{ t("certd.httpProxyHelper") }}</div>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item :label="t('certd.httpsProxy')" :name="['private', 'httpsProxy']" :rules="urlRules">
|
||||||
|
<div class="flex">
|
||||||
|
<a-input v-model:value="formState.private.httpsProxy" :placeholder="t('certd.httpsProxyPlaceholder')" />
|
||||||
|
<a-button class="ml-5" type="primary" :loading="testProxyLoading" :title="t('certd.saveThenTestTitle')" @click="testProxy">{{ t("certd.testButton") }}</a-button>
|
||||||
|
</div>
|
||||||
|
<div class="helper">{{ t("certd.httpsProxyHelper") }}</div>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item :label="t('certd.dualStackNetwork')" :name="['private', 'dnsResultOrder']">
|
||||||
|
<a-select v-model:value="formState.private.dnsResultOrder">
|
||||||
|
<a-select-option value="verbatim">{{ t("certd.default") }}</a-select-option>
|
||||||
|
<a-select-option value="ipv4first">{{ t("certd.ipv4Priority") }}</a-select-option>
|
||||||
|
<a-select-option value="ipv6first">{{ t("certd.ipv6Priority") }}</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
<div class="helper">
|
||||||
|
{{ t("certd.dualStackNetworkHelper") }}, <a href="https://certd.docmirror.cn/guide/use/setting/ipv6.html" target="_blank">{{ t("certd.helpDocLink") }}</a>
|
||||||
|
</div>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item :label="t('certd.sys.setting.reverseProxy')" :name="['private', 'reverseProxy']">
|
||||||
|
<div class="mt-5">
|
||||||
|
<div v-for="(value, key) in formState.private.reverseProxies" :key="key" class="flex items-center p-2 border-b border-gray-300">
|
||||||
|
<span class="flex-1">{{ key }}</span>
|
||||||
|
<span class="flex-1 ml-5"><a-input v-model:value="formState.private.reverseProxies[key]" placeholder="proxy.xxxx.com" allow-clear /></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="helper">{{ t("certd.sys.setting.reverseProxyHelper") }}</div>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item label=" " :colon="false" :wrapper-col="{ span: 8 }">
|
||||||
|
<a-button :loading="saveLoading" type="primary" html-type="submit">{{ t("certd.saveButton") }}</a-button>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="tsx">
|
||||||
|
import { proxyRefs, reactive, ref } from "vue";
|
||||||
|
import { SysSettings } from "/@/views/sys/settings/api";
|
||||||
|
import * as api from "/@/views/sys/settings/api";
|
||||||
|
import { merge } from "lodash-es";
|
||||||
|
import { useSettingStore } from "/@/store/settings";
|
||||||
|
import { message, notification } from "ant-design-vue";
|
||||||
|
import { useI18n } from "/src/locales";
|
||||||
|
const { t } = useI18n();
|
||||||
|
import { util } from "/@/utils";
|
||||||
|
defineOptions({
|
||||||
|
name: "SettingNetwork",
|
||||||
|
});
|
||||||
|
|
||||||
|
const formState = reactive<Partial<SysSettings>>({
|
||||||
|
public: {},
|
||||||
|
private: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
const urlRules = ref({
|
||||||
|
type: "url",
|
||||||
|
message: "请输入正确的URL",
|
||||||
|
});
|
||||||
|
|
||||||
|
async function loadSysSettings() {
|
||||||
|
const data: any = await api.SysSettingsGet();
|
||||||
|
merge(formState, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
const saveLoading = ref(false);
|
||||||
|
loadSysSettings();
|
||||||
|
const settingsStore = useSettingStore();
|
||||||
|
const onFinish = async (form: any) => {
|
||||||
|
try {
|
||||||
|
saveLoading.value = true;
|
||||||
|
form.private.reverseProxies = formState.private.reverseProxies;
|
||||||
|
await api.SysSettingsSave(form);
|
||||||
|
await settingsStore.loadSysSettings();
|
||||||
|
notification.success({
|
||||||
|
message: t("certd.saveSuccess"),
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
saveLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const testProxyLoading = ref(false);
|
||||||
|
async function testProxy() {
|
||||||
|
testProxyLoading.value = true;
|
||||||
|
try {
|
||||||
|
const res = await api.TestProxy();
|
||||||
|
let success = true;
|
||||||
|
if (res.google !== true || res.baidu !== true) {
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
const content = () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
{t("certd.google")}: {res.google === true ? t("certd.success") : util.maxLength(res.google)}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{t("certd.baidu")}: {res.baidu === true ? t("certd.success") : util.maxLength(res.baidu)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
if (!success) {
|
||||||
|
notification.error({
|
||||||
|
message: t("certd.testFailed"),
|
||||||
|
description: content,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
notification.success({
|
||||||
|
message: t("certd.testCompleted"),
|
||||||
|
description: content,
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
testProxyLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less"></style>
|
||||||
@@ -8,6 +8,10 @@
|
|||||||
<a-input-number v-model:value="formState.public.limitUserPipelineCount" />
|
<a-input-number v-model:value="formState.public.limitUserPipelineCount" />
|
||||||
<div class="helper">{{ t("certd.limitUserPipelineCountHelper") }}</div>
|
<div class="helper">{{ t("certd.limitUserPipelineCountHelper") }}</div>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item :label="t('certd.sys.setting.showRunStrategy')" :name="['public', 'showRunStrategy']">
|
||||||
|
<a-switch v-model:checked="formState.public.showRunStrategy" />
|
||||||
|
<div class="helper">{{ t("certd.sys.setting.showRunStrategyHelper") }}</div>
|
||||||
|
</a-form-item>
|
||||||
<a-form-item :label="t('certd.sys.setting.pipelineValidTimeEnabled')" :name="['public', 'pipelineValidTimeEnabled']">
|
<a-form-item :label="t('certd.sys.setting.pipelineValidTimeEnabled')" :name="['public', 'pipelineValidTimeEnabled']">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<a-switch v-model:checked="formState.public.pipelineValidTimeEnabled" :disabled="!settingsStore.isPlus" />
|
<a-switch v-model:checked="formState.public.pipelineValidTimeEnabled" :disabled="!settingsStore.isPlus" />
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import * as acme from "@certd/acme-client";
|
import * as acme from "@certd/acme-client";
|
||||||
import { ClientExternalAccountBindingOptions, UrlMapping } from "@certd/acme-client";
|
import { ClientExternalAccountBindingOptions, UrlMapping } from "@certd/acme-client";
|
||||||
import * as _ from "lodash-es";
|
|
||||||
import { Challenge } from "@certd/acme-client/types/rfc8555.js";
|
import { Challenge } from "@certd/acme-client/types/rfc8555.js";
|
||||||
import { IContext } from "@certd/pipeline";
|
|
||||||
import { ILogger, utils } from "@certd/basic";
|
import { ILogger, utils } from "@certd/basic";
|
||||||
|
import { IContext } from "@certd/pipeline";
|
||||||
|
import { IDnsProvider, IDomainParser } from "@certd/plugin-lib";
|
||||||
import punycode from "punycode.js";
|
import punycode from "punycode.js";
|
||||||
import { IOssClient } from "../../../plugin-lib/index.js";
|
import { IOssClient } from "../../../plugin-lib/index.js";
|
||||||
import { IDnsProvider, IDomainParser } from "@certd/plugin-lib";
|
|
||||||
export type CnameVerifyPlan = {
|
export type CnameVerifyPlan = {
|
||||||
type?: string;
|
type?: string;
|
||||||
domain: string;
|
domain: string;
|
||||||
@@ -112,11 +111,26 @@ export class AcmeService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getAcmeClient(email: string): Promise<acme.Client> {
|
async getAcmeClient(email: string): Promise<acme.Client> {
|
||||||
const mappings = {};
|
|
||||||
if (this.sslProvider === "letsencrypt") {
|
const directoryUrl = acme.getDirectoryUrl({ sslProvider: this.sslProvider, pkType: this.options.privateKeyType });
|
||||||
mappings["acme-v02.api.letsencrypt.org"] = this.options.reverseProxy || "le.px.certd.handfree.work";
|
let targetUrl = directoryUrl.replace("https://", "");
|
||||||
} else if (this.sslProvider === "google") {
|
targetUrl = targetUrl.substring(0, targetUrl.indexOf("/"));
|
||||||
mappings["dv.acme-v02.api.pki.goog"] = this.options.reverseProxy || "gg.px.certd.handfree.work";
|
|
||||||
|
const mappings = {
|
||||||
|
"acme-v02.api.letsencrypt.org": "le.px.certd.handfree.work",
|
||||||
|
"dv.acme-v02.api.pki.goog": "gg.px.certd.handfree.work",
|
||||||
|
};
|
||||||
|
const reverseProxies = acme.getSslProviderReverseProxies();
|
||||||
|
if (reverseProxies) {
|
||||||
|
for (const key in reverseProxies) {
|
||||||
|
const value = reverseProxies[key];
|
||||||
|
if (value) {
|
||||||
|
mappings[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.options.reverseProxy && targetUrl) {
|
||||||
|
mappings[targetUrl] = this.options.reverseProxy;
|
||||||
}
|
}
|
||||||
const urlMapping: UrlMapping = {
|
const urlMapping: UrlMapping = {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
@@ -128,7 +142,7 @@ export class AcmeService {
|
|||||||
await this.saveAccountConfig(email, conf);
|
await this.saveAccountConfig(email, conf);
|
||||||
this.logger.info(`创建新的Accountkey:${email}`);
|
this.logger.info(`创建新的Accountkey:${email}`);
|
||||||
}
|
}
|
||||||
const directoryUrl = acme.getDirectoryUrl({ sslProvider: this.sslProvider, pkType: this.options.privateKeyType });
|
|
||||||
if (this.options.useMappingProxy) {
|
if (this.options.useMappingProxy) {
|
||||||
urlMapping.enabled = true;
|
urlMapping.enabled = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -147,7 +161,7 @@ export class AcmeService {
|
|||||||
externalAccountBinding: this.eab,
|
externalAccountBinding: this.eab,
|
||||||
backoffAttempts: this.options.maxCheckRetryCount || 20,
|
backoffAttempts: this.options.maxCheckRetryCount || 20,
|
||||||
backoffMin: 5000,
|
backoffMin: 5000,
|
||||||
backoffMax: 30*1000,
|
backoffMax: 30 * 1000,
|
||||||
urlMapping,
|
urlMapping,
|
||||||
signal: this.options.signal,
|
signal: this.options.signal,
|
||||||
logger: this.logger,
|
logger: this.logger,
|
||||||
@@ -434,11 +448,7 @@ export class AcmeService {
|
|||||||
if (domains.length === 0) {
|
if (domains.length === 0) {
|
||||||
throw new Error("domain can not be empty");
|
throw new Error("domain can not be empty");
|
||||||
}
|
}
|
||||||
// const commonName = domains[0];
|
|
||||||
// let altNames: undefined | string[] = undefined;
|
|
||||||
// if (domains.length > 1) {
|
|
||||||
// altNames = _.slice(domains, 1);
|
|
||||||
// }
|
|
||||||
return {
|
return {
|
||||||
// commonName,
|
// commonName,
|
||||||
altNames: domains,
|
altNames: domains,
|
||||||
|
|||||||
@@ -458,6 +458,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
|||||||
this.eab = eab;
|
this.eab = eab;
|
||||||
const subDomainsGetter = await this.ctx.serviceGetter.get<ISubDomainsGetter>("subDomainsGetter");
|
const subDomainsGetter = await this.ctx.serviceGetter.get<ISubDomainsGetter>("subDomainsGetter");
|
||||||
const domainParser = new DomainParser(subDomainsGetter, this.logger);
|
const domainParser = new DomainParser(subDomainsGetter, this.logger);
|
||||||
|
|
||||||
this.acme = new AcmeService({
|
this.acme = new AcmeService({
|
||||||
userId: this.ctx.user.id,
|
userId: this.ctx.user.id,
|
||||||
userContext: this.userContext,
|
userContext: this.userContext,
|
||||||
@@ -673,6 +674,12 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async onGetReverseProxyList() {
|
||||||
|
const sysSettingsService:any = await this.ctx.serviceGetter.get("sysSettingsService");
|
||||||
|
const sysSettings = await sysSettingsService.getPrivateSettings();
|
||||||
|
return sysSettings.reverseProxyList || []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
new CertApplyPlugin();
|
new CertApplyPlugin();
|
||||||
|
|||||||
Reference in New Issue
Block a user