mirror of https://github.com/certd/certd
pref: 安全特性支持,站点隐藏功能
parent
251b0c58de
commit
d76d56fcce
|
@ -1,158 +1,166 @@
|
|||
import { defineConfig } from "vitepress";
|
||||
import {defineConfig} from "vitepress";
|
||||
// Import lightbox plugin
|
||||
import lightbox from "vitepress-plugin-lightbox";
|
||||
|
||||
// https://vitepress.dev/reference/site-config
|
||||
export default defineConfig({
|
||||
title: "Certd",
|
||||
titleTemplate: "开源SSL证书管理工具,证书自动化申请部署,让你的网站证书永不过期",
|
||||
description: "Certd帮助文档,Certd是一款开源免费的全自动SSL证书管理工具;证书自动化申请部署流水线;自动证书申请、更新、续期;通配符证书,泛域名证书申请;证书自动化部署到阿里云、腾讯云、主机、群晖、宝塔。",
|
||||
markdown: {
|
||||
config: (md) => {
|
||||
// Use lightbox plugin
|
||||
md.use(lightbox, {});
|
||||
}
|
||||
},
|
||||
sitemap: {
|
||||
hostname: 'https://certd.docmirror.cn'
|
||||
},
|
||||
head: [
|
||||
// [
|
||||
// 'meta',
|
||||
// {
|
||||
// name: 'viewport',
|
||||
// content:
|
||||
// 'width=device-width,initial-scale=1,minimfast-cum-scale=1.0,maximum-scale=1.0,user-scalable=no',
|
||||
// },
|
||||
// ],
|
||||
["meta", {
|
||||
name: "keywords",
|
||||
content: "证书自动申请、证书自动更新、证书自动续期、证书自动续签、证书管理工具、Certd、SSL证书自动部署、证书自动化,https证书,pfx证书,der证书,TLS证书,nginx证书自动续签自动部署,SSL平台,证书管理平台,证书流水线"
|
||||
}],
|
||||
// ["meta", { name: "google-site-verification",content: "V5XLTSnXoT15uQotwpxJoQolUo2d5UbSL-TacsyOsC0"}],
|
||||
//<meta name="baidu-site-verification" content="codeva-MiWN8Y07Ua" />
|
||||
// ["meta", {name: "baidu-site-verification",content: "codeva-MiWN8Y07Ua"}],
|
||||
["link", { rel: "icon", href: "/static/logo/logo.svg" }]
|
||||
],
|
||||
themeConfig: {
|
||||
logo: "/static/logo/logo.svg",
|
||||
search: {
|
||||
provider: "local",
|
||||
options: {
|
||||
detailedView: true,
|
||||
translations: {
|
||||
button: {
|
||||
buttonText: "搜索文档",
|
||||
buttonAriaLabel: "搜索文档"
|
||||
},
|
||||
modal: {
|
||||
noResultsText: "无法找到相关结果",
|
||||
resetButtonTitle: "清除查询条件",
|
||||
footer: {
|
||||
selectText: "选择",
|
||||
closeText: "关闭",
|
||||
navigateText: "切换"
|
||||
title: "Certd",
|
||||
titleTemplate: "开源SSL证书管理工具,证书自动化申请部署,让你的网站证书永不过期",
|
||||
description: "Certd帮助文档,Certd是一款开源免费的全自动SSL证书管理工具;证书自动化申请部署流水线;自动证书申请、更新、续期;通配符证书,泛域名证书申请;证书自动化部署到阿里云、腾讯云、主机、群晖、宝塔。",
|
||||
markdown: {
|
||||
config: (md) => {
|
||||
// Use lightbox plugin
|
||||
md.use(lightbox, {});
|
||||
}
|
||||
},
|
||||
sitemap: {
|
||||
hostname: 'https://certd.docmirror.cn'
|
||||
},
|
||||
head: [
|
||||
// [
|
||||
// 'meta',
|
||||
// {
|
||||
// name: 'viewport',
|
||||
// content:
|
||||
// 'width=device-width,initial-scale=1,minimfast-cum-scale=1.0,maximum-scale=1.0,user-scalable=no',
|
||||
// },
|
||||
// ],
|
||||
["meta", {
|
||||
name: "keywords",
|
||||
content: "证书自动申请、证书自动更新、证书自动续期、证书自动续签、证书管理工具、Certd、SSL证书自动部署、证书自动化,https证书,pfx证书,der证书,TLS证书,nginx证书自动续签自动部署,SSL平台,证书管理平台,证书流水线"
|
||||
}],
|
||||
// ["meta", { name: "google-site-verification",content: "V5XLTSnXoT15uQotwpxJoQolUo2d5UbSL-TacsyOsC0"}],
|
||||
//<meta name="baidu-site-verification" content="codeva-MiWN8Y07Ua" />
|
||||
// ["meta", {name: "baidu-site-verification",content: "codeva-MiWN8Y07Ua"}],
|
||||
["link", {rel: "icon", href: "/static/logo/logo.svg"}]
|
||||
],
|
||||
themeConfig: {
|
||||
logo: "/static/logo/logo.svg",
|
||||
search: {
|
||||
provider: "local",
|
||||
options: {
|
||||
detailedView: true,
|
||||
translations: {
|
||||
button: {
|
||||
buttonText: "搜索文档",
|
||||
buttonAriaLabel: "搜索文档"
|
||||
},
|
||||
modal: {
|
||||
noResultsText: "无法找到相关结果",
|
||||
resetButtonTitle: "清除查询条件",
|
||||
footer: {
|
||||
selectText: "选择",
|
||||
closeText: "关闭",
|
||||
navigateText: "切换"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// https://vitepress.dev/reference/default-theme-config
|
||||
nav: [
|
||||
{ text: "首页", link: "/" },
|
||||
{ text: "指南", link: "/guide/" },
|
||||
{ text: "插件", link: "/deploy/" },
|
||||
{ text: "商业版", link: "/comm/" },
|
||||
{ text: "Demo体验", link: "https://certd.handfree.work" }
|
||||
],
|
||||
sidebar: {
|
||||
"/guide/": [
|
||||
{
|
||||
text: "入门",
|
||||
items: [
|
||||
{ text: "简介", link: "/guide/" },
|
||||
{ text: "快速开始", link: "/guide/start.md" },
|
||||
{
|
||||
text: "私有化部署",
|
||||
items: [
|
||||
{ text: "docker部署", link: "/guide/install/docker/" },
|
||||
{ text: "宝塔面板部署", link: "/guide/install/baota/" },
|
||||
{ text: "1Panel部署", link: "/guide/install/1panel/" },
|
||||
{ text: "群晖部署", link: "/guide/use/synology/" },
|
||||
{ text: "源码部署", link: "/guide/install/source/" }
|
||||
]
|
||||
},
|
||||
{ text: "演示教程", link: "/guide/tutorial.md" },
|
||||
{ text: "版本升级", link: "/guide/install/upgrade.md" }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: "特性",
|
||||
items: [
|
||||
{ text: "CNAME代理校验", link: "/guide/feature/cname/index.md" },
|
||||
{ text: "插件列表", link: "/guide/plugins.md" },
|
||||
{ text: "多数据库支持", link: "/guide/install/database.md" },
|
||||
{ text: "开放接口", link: "/guide/open/index.md" }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: "常见问题",
|
||||
items: [
|
||||
{ text: "群晖证书部署", link: "/guide/use/synology/" },
|
||||
{ text: "腾讯云密钥获取", link: "/guide/use/tencent/" },
|
||||
{ text: "连接windows主机", link: "/guide/use/host/windows.md" },
|
||||
{ text: "Google EAB获取", link: "/guide/use/google/" },
|
||||
{ text: "阿里云相关", link: "/guide/use/aliyun/" },
|
||||
{ text: "忘记密码", link: "/guide/use/forgotpasswd/" },
|
||||
{ text: "数据备份", link: "/guide/use/backup/" },
|
||||
{ text: "Certd本身的证书更新", link: "/guide/use/https/index.md" },
|
||||
{ text: "js脚本插件使用", link: "/guide/use/custom-script/index.md" },
|
||||
{ text: "邮箱配置", link: "/guide/use/email/index.md" },
|
||||
{ text: "IPv6支持", link: "/guide/use/setting/ipv6.md" },
|
||||
]
|
||||
},
|
||||
{
|
||||
text: "其他",
|
||||
items: [
|
||||
{ text: "贡献代码", link: "/guide/development/index.md" },
|
||||
{ text: "更新日志", link: "/guide/changelogs/CHANGELOG.md" },
|
||||
{ text: "镜像说明", link: "/guide/image.md" },
|
||||
{ text: "联系我们", link: "/guide/contact/" },
|
||||
{ text: "捐赠", link: "/guide/donate/" },
|
||||
{ text: "开源协议", link: "/guide/license/" },
|
||||
{ text: "我的其他开源项目", link: "/guide/link/" },
|
||||
// https://vitepress.dev/reference/default-theme-config
|
||||
nav: [
|
||||
{text: "首页", link: "/"},
|
||||
{text: "指南", link: "/guide/"},
|
||||
{text: "Demo体验", link: "https://certd.handfree.work"}
|
||||
],
|
||||
sidebar: {
|
||||
"/guide/": [
|
||||
{
|
||||
text: "入门",
|
||||
items: [
|
||||
{text: "简介", link: "/guide/"},
|
||||
{text: "快速开始", link: "/guide/start.md"},
|
||||
{
|
||||
text: "私有化部署",
|
||||
items: [
|
||||
{text: "docker部署", link: "/guide/install/docker/"},
|
||||
{text: "宝塔面板部署", link: "/guide/install/baota/"},
|
||||
{text: "1Panel部署", link: "/guide/install/1panel/"},
|
||||
{text: "群晖部署", link: "/guide/use/synology/"},
|
||||
{text: "源码部署", link: "/guide/install/source/"}
|
||||
]
|
||||
},
|
||||
{text: "演示教程", link: "/guide/tutorial.md"},
|
||||
{text: "版本升级", link: "/guide/install/upgrade.md"}
|
||||
]
|
||||
},
|
||||
{
|
||||
text: "特性",
|
||||
items: [
|
||||
{text: "CNAME代理校验", link: "/guide/feature/cname/index.md"},
|
||||
{text: "插件列表", link: "/guide/plugins.md"},
|
||||
{text: "多数据库支持", link: "/guide/install/database.md"},
|
||||
{text: "开放接口", link: "/guide/open/index.md"},
|
||||
{
|
||||
text: "站点安全", items: [
|
||||
{text: "安全特性", link: "/guide/feature/safe"},
|
||||
{text: "站点隐藏", link: "/guide/feature/safe/hidden"},
|
||||
{text: "安全生产建议", link: "/guide/feature/safe/suggest"},
|
||||
]
|
||||
},
|
||||
|
||||
]
|
||||
}
|
||||
],
|
||||
"/deploy/":[
|
||||
{
|
||||
text: "部署证书插件",
|
||||
items: [
|
||||
{ text: "插件说明", link: "/deploy/index.md" },
|
||||
{ text: "部署到ESXi", link: "/deploy/ESXi/index.md" },
|
||||
]
|
||||
}
|
||||
],
|
||||
"/comm/": [
|
||||
{
|
||||
text: "商业版",
|
||||
items: [
|
||||
{ text: "支付宝配置", link: "/comm/payments/alipay.md" },
|
||||
{ text: "微信支付配置", link: "/comm/payments/wxpay.md" },
|
||||
{ text: "彩虹易支付配置", link: "/comm/payments/yizhifu.md" },
|
||||
]
|
||||
}
|
||||
]
|
||||
,
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
text: "常见问题",
|
||||
items: [
|
||||
{text: "群晖证书部署", link: "/guide/use/synology/"},
|
||||
{text: "腾讯云密钥获取", link: "/guide/use/tencent/"},
|
||||
{text: "连接windows主机", link: "/guide/use/host/windows.md"},
|
||||
{text: "Google EAB获取", link: "/guide/use/google/"},
|
||||
{text: "阿里云相关", link: "/guide/use/aliyun/"},
|
||||
{text: "忘记密码", link: "/guide/use/forgotpasswd/"},
|
||||
{text: "数据备份", link: "/guide/use/backup/"},
|
||||
{text: "Certd本身的证书更新", link: "/guide/use/https/index.md"},
|
||||
{text: "js脚本插件使用", link: "/guide/use/custom-script/index.md"},
|
||||
{text: "邮箱配置", link: "/guide/use/email/index.md"},
|
||||
{text: "IPv6支持", link: "/guide/use/setting/ipv6.md"},
|
||||
{text: "其他插件使用", link: "/deploy/"},
|
||||
{text: "商业版说明", link: "/comm/"},
|
||||
]
|
||||
},
|
||||
{
|
||||
text: "其他",
|
||||
items: [
|
||||
{text: "贡献代码", link: "/guide/development/index.md"},
|
||||
{text: "更新日志", link: "/guide/changelogs/CHANGELOG.md"},
|
||||
{text: "镜像说明", link: "/guide/image.md"},
|
||||
{text: "联系我们", link: "/guide/contact/"},
|
||||
{text: "捐赠", link: "/guide/donate/"},
|
||||
{text: "开源协议", link: "/guide/license/"},
|
||||
{text: "我的其他开源项目", link: "/guide/link/"},
|
||||
|
||||
socialLinks: [
|
||||
{ icon: "github", link: "https://github.com/certd/certd" }
|
||||
],
|
||||
footer: {
|
||||
message: "Certd帮助文档 | <a href='https://beian.miit.gov.cn/' target='_blank'>粤ICP备14088435号</a> ",
|
||||
copyright: "Copyright © 2021-present <a href='https://handfree.work/' target='_blank'>handfree.work</a> "
|
||||
]
|
||||
}
|
||||
],
|
||||
"/deploy/": [
|
||||
{
|
||||
text: "部署证书插件",
|
||||
items: [
|
||||
{text: "插件说明", link: "/deploy/index.md"},
|
||||
{text: "部署到ESXi", link: "/deploy/ESXi/index.md"},
|
||||
]
|
||||
}
|
||||
],
|
||||
"/comm/": [
|
||||
{
|
||||
text: "商业版",
|
||||
items: [
|
||||
{text: "支付宝配置", link: "/comm/payments/alipay.md"},
|
||||
{text: "微信支付配置", link: "/comm/payments/wxpay.md"},
|
||||
{text: "彩虹易支付配置", link: "/comm/payments/yizhifu.md"},
|
||||
]
|
||||
}
|
||||
]
|
||||
,
|
||||
},
|
||||
|
||||
socialLinks: [
|
||||
{icon: "github", link: "https://github.com/certd/certd"}
|
||||
],
|
||||
footer: {
|
||||
message: "Certd帮助文档 | <a href='https://beian.miit.gov.cn/' target='_blank'>粤ICP备14088435号</a> ",
|
||||
copyright: "Copyright © 2021-present <a href='https://handfree.work/' target='_blank'>handfree.work</a> "
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 51 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.3 KiB |
|
@ -0,0 +1,25 @@
|
|||
# 站点隐藏
|
||||
|
||||
* 一般来说Certd设置好之后,很少需要访问。
|
||||
* 所以我们`平时`可以把`站点访问关闭`,需要的时候再打开,减少站点被攻击的风险
|
||||
|
||||
## 1、开启站点隐藏
|
||||
`系统管理->系统设置->安全设置->站点隐藏 `
|
||||
|
||||
|
||||

|
||||
|
||||
:::warning
|
||||
|
||||
注意保存好`解除地址`和`解除密码`
|
||||
|
||||
:::
|
||||
|
||||
## 2、临时关闭站点隐藏
|
||||
|
||||
访问上面的`解除地址`,输入`解除密码`,`临时解除`站点隐藏
|
||||
|
||||

|
||||
|
||||
## 3、忘记解除地址和解除密码怎么办
|
||||
登录服务器,在数据库平级的目录下创建`.unhidden`文件即可`临时解除`站点隐藏
|
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
Binary file not shown.
After Width: | Height: | Size: 35 KiB |
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
|
@ -0,0 +1,34 @@
|
|||
# 站点安全特性
|
||||
|
||||
Certd 存储了证书以及授权等敏感数据,所以需要严格保障安全。
|
||||
我们非常重视您的数据安全,提供了以下安全特性
|
||||
|
||||
## 1、 授权数据加密存储【默认开启】
|
||||
* 所有的授权敏感字段会加密后存储
|
||||
* 每个用户独立维护授权数据,连管理员都无权查看
|
||||
|
||||

|
||||
星号部分为加密数据
|
||||
|
||||
## 2、 密码防爆破【默认开启】
|
||||
* 登录失败次数过多,账号将被锁定,最高24小时(重启服务可解除锁定)
|
||||
* 用户登录密码加密hash后存储,无法计算出密码明文
|
||||

|
||||
|
||||
## 3、站点隐藏【建议开启】
|
||||
* 一般来说Certd设置好之后,后续很少需要访问修改。
|
||||
* 所以我们平时可以把站点访问关闭,需要的时候再打开,减少站点被攻击的风险
|
||||
* 请前往 `系统管理->系统设置->安全设置->开启站点隐藏`
|
||||
* [站点隐藏设置说明](./hidden/)
|
||||

|
||||
|
||||
## 4、登录二次验证
|
||||
|
||||
待实现
|
||||
|
||||
## 5、数据库自动备份【建议开启】
|
||||
* [自动备份设置说明](../../use/backup/)
|
||||
|
||||
|
||||
## 更多安全生产建议
|
||||
[安全生产建议](./suggest.md)
|
|
@ -0,0 +1,10 @@
|
|||
# 安全生产建议
|
||||
|
||||
尽管`Cert`本身实现了很多安全特性,但`外部环境的安全`仍需要您来确保。
|
||||
请`务必`遵循如下建议做好安全防护
|
||||
|
||||
* 请`务必`使用`HTTPS协议`访问本应用,避免被中间人攻击
|
||||
* 请`务必`使用`web应用防火墙`防护本应用,防止XSS、SQL注入等攻击
|
||||
* 请`务必`做好`服务器本身`的安全防护,防止数据库泄露
|
||||
* 请`务必`做好[`数据备份`](../../use/backup/),避免数据丢失
|
||||
* 建议开启[`站点隐藏`](./hidden/)功能
|
|
@ -1,18 +1,18 @@
|
|||
import crypto, { BinaryToTextEncoding } from 'crypto';
|
||||
import crypto, { BinaryToTextEncoding } from "crypto";
|
||||
|
||||
function md5(data: string, digest: BinaryToTextEncoding = 'hex') {
|
||||
return crypto.createHash('md5').update(data).digest(digest);
|
||||
function md5(data: string, digest: BinaryToTextEncoding = "hex") {
|
||||
return crypto.createHash("md5").update(data).digest(digest);
|
||||
}
|
||||
function sha256(data: string, digest: BinaryToTextEncoding = 'hex') {
|
||||
return crypto.createHash('sha256').update(data).digest(digest);
|
||||
function sha256(data: string, digest: BinaryToTextEncoding = "hex") {
|
||||
return crypto.createHash("sha256").update(data).digest(digest);
|
||||
}
|
||||
|
||||
function hmacSha256(data: string, digest: BinaryToTextEncoding = 'base64') {
|
||||
return crypto.createHmac('sha256', data).update(Buffer.alloc(0)).digest(digest);
|
||||
function hmacSha256(data: string, digest: BinaryToTextEncoding = "base64") {
|
||||
return crypto.createHmac("sha256", data).update(Buffer.alloc(0)).digest(digest);
|
||||
}
|
||||
|
||||
function base64(data: string) {
|
||||
return Buffer.from(data).toString('base64');
|
||||
return Buffer.from(data).toString("base64");
|
||||
}
|
||||
export const hashUtils = {
|
||||
md5,
|
||||
|
|
|
@ -66,10 +66,15 @@ export const Constants = {
|
|||
code: 404,
|
||||
message: '页面/文件/资源不存在',
|
||||
},
|
||||
|
||||
preview: {
|
||||
code: 10001,
|
||||
message: '对不起,预览环境不允许修改此数据',
|
||||
},
|
||||
siteOff:{
|
||||
code: 10010,
|
||||
message: '站点已关闭',
|
||||
},
|
||||
openKeyError: {
|
||||
code: 20000,
|
||||
message: 'ApiToken错误',
|
||||
|
|
|
@ -7,3 +7,4 @@ export * from './vip-exception.js';
|
|||
export * from './common-exception.js';
|
||||
export * from './not-found-exception.js';
|
||||
export * from './param-exception.js';
|
||||
export * from './site-off-exception.js';
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
import { Constants } from '../constants.js';
|
||||
import { BaseException } from './base-exception.js';
|
||||
/**
|
||||
*/
|
||||
export class SiteOffException extends BaseException {
|
||||
constructor(message) {
|
||||
super('SiteOffException', Constants.res.siteOff.code, message ? message : Constants.res.siteOff.message);
|
||||
}
|
||||
}
|
|
@ -171,7 +171,7 @@ export class SysSuiteSetting extends BaseSettings {
|
|||
static __key__ = 'sys.suite';
|
||||
static __access__ = 'private';
|
||||
|
||||
enabled = false;
|
||||
enabled:boolean = false;
|
||||
|
||||
registerGift?: {
|
||||
productId: number;
|
||||
|
@ -180,3 +180,25 @@ export class SysSuiteSetting extends BaseSettings {
|
|||
|
||||
intro?: string;
|
||||
}
|
||||
|
||||
|
||||
export type SiteHidden = {
|
||||
enabled: boolean;
|
||||
openPath?: string;
|
||||
//md5 hash 两次后保存
|
||||
openPassword?: string;
|
||||
autoHiddenTimes?: number;
|
||||
hiddenOpenApi?: boolean
|
||||
};
|
||||
export class SysSafeSetting extends BaseSettings {
|
||||
static __title__ = '站点安全设置';
|
||||
static __key__ = 'sys.safe';
|
||||
static __access__ = 'private';
|
||||
|
||||
// 站点隐藏
|
||||
hidden:SiteHidden = {
|
||||
enabled: false,
|
||||
hiddenOpenApi:false,
|
||||
autoHiddenTimes: 5,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -84,6 +84,7 @@
|
|||
"qrcode": "^1.5.4",
|
||||
"radix-vue": "^1.9.16",
|
||||
"sortablejs": "^1.15.3",
|
||||
"spark-md5": "^3.0.2",
|
||||
"tailwind-merge": "^3.0.2",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"theme-colors": "^0.1.0",
|
||||
|
|
|
@ -54,23 +54,23 @@ const steps = ref<Step[]>([
|
|||
descriptions: ["本教程演示如何自动申请证书并部署到Nginx上", "仅需3步,全自动申请部署证书"],
|
||||
body: () => {
|
||||
return <SimpleSteps></SimpleSteps>;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
image: "/static/doc/images/1-add.png",
|
||||
title: "创建证书流水线",
|
||||
descriptions: ["点击添加证书流水线,填写证书申请信息"]
|
||||
descriptions: ["点击添加证书流水线,填写证书申请信息"],
|
||||
},
|
||||
{
|
||||
image: "/static/doc/images/3-add-success.png",
|
||||
title: "流水线创建成功",
|
||||
descriptions: ["点击手动触发即可申请证书"]
|
||||
descriptions: ["点击手动触发即可申请证书"],
|
||||
},
|
||||
{
|
||||
title: "接下来演示如何自动部署证书",
|
||||
descriptions: ["如果您只需要申请证书,那么到这一步就可以了"]
|
||||
}
|
||||
]
|
||||
descriptions: ["如果您只需要申请证书,那么到这一步就可以了"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "添加部署证书任务",
|
||||
|
@ -79,29 +79,29 @@ const steps = ref<Step[]>([
|
|||
{
|
||||
image: "/static/doc/images/5-1-add-host.png",
|
||||
title: "添加证书部署任务",
|
||||
descriptions: ["这里演示自动部署证书到nginx", "本系统提供海量部署插件,满足您的各种部署需求"]
|
||||
descriptions: ["这里演示自动部署证书到nginx", "本系统提供海量部署插件,满足您的各种部署需求"],
|
||||
},
|
||||
{
|
||||
image: "/static/doc/images/5-2-add-host.png",
|
||||
title: "填写任务参数",
|
||||
descriptions: ["填写主机上证书文件的路径", "选择主机ssh登录授权"]
|
||||
descriptions: ["填写主机上证书文件的路径", "选择主机ssh登录授权"],
|
||||
},
|
||||
{
|
||||
image: "/static/doc/images/5-3-add-host.png",
|
||||
title: "让新证书生效",
|
||||
descriptions: ["执行重启脚本", "让证书生效"]
|
||||
descriptions: ["执行重启脚本", "让证书生效"],
|
||||
},
|
||||
{
|
||||
image: "/static/doc/images/5-4-add-host.png",
|
||||
title: "部署任务添加成功",
|
||||
descriptions: ["现在可以运行"]
|
||||
descriptions: ["现在可以运行"],
|
||||
},
|
||||
{
|
||||
image: "/static/doc/images/5-5-plugin-list.png",
|
||||
title: "本系统提供茫茫多的部署插件",
|
||||
descriptions: ["您可以根据自身需求将证书部署到各种应用和平台"]
|
||||
}
|
||||
]
|
||||
descriptions: ["您可以根据自身需求将证书部署到各种应用和平台"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "运行与测试",
|
||||
|
@ -110,44 +110,44 @@ const steps = ref<Step[]>([
|
|||
{
|
||||
image: "/static/doc/images/9-start.png",
|
||||
title: "运行测试一下",
|
||||
descriptions: ["点击手动触发按钮,即可测试运行"]
|
||||
descriptions: ["点击手动触发按钮,即可测试运行"],
|
||||
},
|
||||
{
|
||||
image: "/static/doc/images/10-1-log.png",
|
||||
title: "查看日志",
|
||||
descriptions: ["点击任务可以查看状态和日志"]
|
||||
descriptions: ["点击任务可以查看状态和日志"],
|
||||
},
|
||||
{
|
||||
image: "/static/doc/images/11-1-error.png",
|
||||
title: "执行失败如何排查",
|
||||
descriptions: ["查看错误日志"]
|
||||
descriptions: ["查看错误日志"],
|
||||
},
|
||||
{
|
||||
image: "/static/doc/images/11-2-error.png",
|
||||
title: "执行失败如何排查",
|
||||
descriptions: ["查看错误日志", "这里报的是nginx容器不存在,修改命令,改成正确的nginx容器名称即可"]
|
||||
descriptions: ["查看错误日志", "这里报的是nginx容器不存在,修改命令,改成正确的nginx容器名称即可"],
|
||||
},
|
||||
{
|
||||
image: "/static/doc/images/12-1-log-success.png",
|
||||
title: "执行成功",
|
||||
descriptions: ["修改正确后,重新点击手动触发,重新运行一次,执行成功"]
|
||||
descriptions: ["修改正确后,重新点击手动触发,重新运行一次,执行成功"],
|
||||
},
|
||||
{
|
||||
image: "/static/doc/images/12-2-skip-log.png",
|
||||
title: "成功后自动跳过",
|
||||
descriptions: ["可以看到成功过的将会自动跳过,不会重复执行,只有当参数变更或者证书更新了,才会重新运行"]
|
||||
descriptions: ["可以看到成功过的将会自动跳过,不会重复执行,只有当参数变更或者证书更新了,才会重新运行"],
|
||||
},
|
||||
{
|
||||
image: "/static/doc/images/13-1-result.png",
|
||||
title: "查看证书部署成功",
|
||||
descriptions: ["访问nginx上的网站,可以看到证书已经部署成功"]
|
||||
descriptions: ["访问nginx上的网站,可以看到证书已经部署成功"],
|
||||
},
|
||||
{
|
||||
image: "/static/doc/images/13-3-download.png",
|
||||
title: "还可以下载证书,手动部署",
|
||||
descriptions: ["如果还没有好用的部署插件,没办法自动部署,你还可以下载证书,手动部署"]
|
||||
}
|
||||
]
|
||||
descriptions: ["如果还没有好用的部署插件,没办法自动部署,你还可以下载证书,手动部署"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "设置定时执行和邮件通知",
|
||||
|
@ -156,22 +156,19 @@ const steps = ref<Step[]>([
|
|||
{
|
||||
image: "/static/doc/images/14-timer.png",
|
||||
title: "设置定时执行",
|
||||
descriptions: [
|
||||
"流水线测试成功,接下来配置定时触发,以后每天定时执行就不用管了",
|
||||
"推荐配置每天运行一次,在到期前35天才会重新申请新证书并部署,没到期前会自动跳过,不会重复申请。"
|
||||
]
|
||||
descriptions: ["流水线测试成功,接下来配置定时触发,以后每天定时执行就不用管了", "推荐配置每天运行一次,在到期前35天才会重新申请新证书并部署,没到期前会自动跳过,不会重复申请。"],
|
||||
},
|
||||
{
|
||||
image: "/static/doc/images/15-1-email.png",
|
||||
title: "设置邮件通知",
|
||||
descriptions: ["建议选择监听'错误时'和'错误转成功'两种即可,在意外失败时可以尽快去排查问题,(基础版需要配置邮件服务器)"]
|
||||
descriptions: ["建议选择监听'错误时'和'错误转成功'两种即可,在意外失败时可以尽快去排查问题,(基础版需要配置邮件服务器)"],
|
||||
},
|
||||
{
|
||||
title: "教程结束",
|
||||
descriptions: ["感谢观看,希望对你有所帮助"]
|
||||
}
|
||||
]
|
||||
}
|
||||
descriptions: ["感谢观看,希望对你有所帮助"],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
const current = ref(0);
|
||||
|
|
|
@ -16,6 +16,6 @@ export const util = {
|
|||
router: routerUtils,
|
||||
tree: treeUtils,
|
||||
hash: hashUtils,
|
||||
amount: amountUtils
|
||||
amount: amountUtils,
|
||||
};
|
||||
export const utils = util;
|
||||
|
|
|
@ -5,5 +5,5 @@ export const amountUtils = {
|
|||
|
||||
toYuan(amount: number): number {
|
||||
return parseFloat((amount / 100).toFixed(2));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -47,4 +47,13 @@ export default {
|
|||
}
|
||||
return desc.replace(/\[(.*)\]\((.*)\)/g, '<a href="$2" target="_blank">$1</a>');
|
||||
},
|
||||
|
||||
randomString(length: number) {
|
||||
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
let result = "";
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
||||
}
|
||||
return result;
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
export const hashUtils = {
|
||||
md5(data: string) {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -7,5 +7,5 @@ export const site = {
|
|||
title: function (titleText: string, baseTitle?: string) {
|
||||
const processTitle = baseTitle || env.TITLE || "Certd";
|
||||
window.document.title = `${processTitle}${titleText ? ` | ${titleText}` : ""}`;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -46,7 +46,7 @@ export class WebStorage {
|
|||
const stringData = JSON.stringify({
|
||||
value,
|
||||
time: Date.now(),
|
||||
expire: expire != null ? new Date().getTime() + expire * 1000 : null
|
||||
expire: expire != null ? new Date().getTime() + expire * 1000 : null,
|
||||
});
|
||||
this.storage.setItem(this.getKey(key), stringData);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ export async function GetList(query: any) {
|
|||
return await request({
|
||||
url: apiPrefix + "/page",
|
||||
method: "post",
|
||||
data: query
|
||||
data: query,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ export async function AddObj(obj: any) {
|
|||
return await request({
|
||||
url: apiPrefix + "/add",
|
||||
method: "post",
|
||||
data: obj
|
||||
data: obj,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ export async function UpdateObj(obj: any) {
|
|||
return await request({
|
||||
url: apiPrefix + "/update",
|
||||
method: "post",
|
||||
data: obj
|
||||
data: obj,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ export async function DelObj(id: any) {
|
|||
return await request({
|
||||
url: apiPrefix + "/delete",
|
||||
method: "post",
|
||||
params: { id }
|
||||
params: { id },
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,14 @@ export async function GetObj(id: any) {
|
|||
return await request({
|
||||
url: apiPrefix + "/info",
|
||||
method: "post",
|
||||
params: { id }
|
||||
params: { id },
|
||||
});
|
||||
}
|
||||
|
||||
export async function Unlock(id: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/unlockBlock",
|
||||
method: "post",
|
||||
data: { id },
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import * as api from "./api";
|
||||
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
|
||||
import { useUserStore } from "/@/store/user";
|
||||
import { Modal, notification } from "ant-design-vue";
|
||||
|
||||
export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
|
||||
|
@ -26,16 +27,36 @@ export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOpti
|
|||
pageRequest,
|
||||
addRequest,
|
||||
editRequest,
|
||||
delRequest
|
||||
delRequest,
|
||||
},
|
||||
rowHandle: {
|
||||
fixed: "right"
|
||||
fixed: "right",
|
||||
buttons: {
|
||||
unlock: {
|
||||
title: "解除登录锁定",
|
||||
text: null,
|
||||
type: "link",
|
||||
icon: "ion:lock-open-outline",
|
||||
click: async ({ row }) => {
|
||||
Modal.confirm({
|
||||
title: "提示",
|
||||
content: "确定要解除该用户的登录锁定吗?",
|
||||
onOk: async () => {
|
||||
await api.Unlock(row.id);
|
||||
notification.success({
|
||||
message: "解除成功",
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
table: {
|
||||
scroll: {
|
||||
//使用固定列时需要设置此值,并且大于等于列宽度之和的值
|
||||
x: 1400
|
||||
}
|
||||
x: 1400,
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
id: {
|
||||
|
@ -44,8 +65,8 @@ export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOpti
|
|||
form: { show: false }, // 表单配置
|
||||
column: {
|
||||
width: 100,
|
||||
sorter: true
|
||||
}
|
||||
sorter: true,
|
||||
},
|
||||
},
|
||||
createTime: {
|
||||
title: "创建时间",
|
||||
|
@ -53,8 +74,8 @@ export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOpti
|
|||
form: { show: false }, // 表单配置
|
||||
column: {
|
||||
width: 180,
|
||||
sorter: true
|
||||
}
|
||||
sorter: true,
|
||||
},
|
||||
},
|
||||
// updateTime: {
|
||||
// title: "修改时间",
|
||||
|
@ -72,64 +93,64 @@ export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOpti
|
|||
form: {
|
||||
rules: [
|
||||
{ required: true, message: "请输入用户名" },
|
||||
{ max: 50, message: "最大50个字符" }
|
||||
]
|
||||
{ max: 50, message: "最大50个字符" },
|
||||
],
|
||||
},
|
||||
editForm: { component: { disabled: false } },
|
||||
column: {
|
||||
sorter: true,
|
||||
width: 200
|
||||
}
|
||||
width: 200,
|
||||
},
|
||||
},
|
||||
password: {
|
||||
title: "密码",
|
||||
type: "text",
|
||||
key: "password",
|
||||
column: {
|
||||
show: false
|
||||
show: false,
|
||||
},
|
||||
form: {
|
||||
rules: [{ max: 50, message: "最大50个字符" }],
|
||||
component: {
|
||||
showPassword: true
|
||||
showPassword: true,
|
||||
},
|
||||
helper: "填写则修改密码"
|
||||
}
|
||||
helper: "填写则修改密码",
|
||||
},
|
||||
},
|
||||
nickName: {
|
||||
title: "昵称",
|
||||
type: "text",
|
||||
search: { show: true }, // 开启查询
|
||||
form: {
|
||||
rules: [{ max: 50, message: "最大50个字符" }]
|
||||
rules: [{ max: 50, message: "最大50个字符" }],
|
||||
},
|
||||
column: {
|
||||
sorter: true
|
||||
}
|
||||
sorter: true,
|
||||
},
|
||||
},
|
||||
email: {
|
||||
title: "邮箱",
|
||||
type: "text",
|
||||
search: { show: true }, // 开启查询
|
||||
form: {
|
||||
rules: [{ max: 50, message: "最大50个字符" }]
|
||||
rules: [{ max: 50, message: "最大50个字符" }],
|
||||
},
|
||||
column: {
|
||||
sorter: true,
|
||||
width: 160
|
||||
}
|
||||
width: 160,
|
||||
},
|
||||
},
|
||||
mobile: {
|
||||
title: "手机号",
|
||||
type: "text",
|
||||
search: { show: true }, // 开启查询
|
||||
form: {
|
||||
rules: [{ max: 50, message: "最大50个字符" }]
|
||||
rules: [{ max: 50, message: "最大50个字符" }],
|
||||
},
|
||||
column: {
|
||||
sorter: true,
|
||||
width: 130
|
||||
}
|
||||
width: 130,
|
||||
},
|
||||
},
|
||||
avatar: {
|
||||
title: "头像",
|
||||
|
@ -140,12 +161,12 @@ export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOpti
|
|||
//设置高度,修复操作列错位的问题
|
||||
style: {
|
||||
height: "30px",
|
||||
width: "auto"
|
||||
width: "auto",
|
||||
},
|
||||
buildUrl(key: string) {
|
||||
return `/api/basic/file/download?&key=` + key;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
form: {
|
||||
component: {
|
||||
|
@ -154,7 +175,7 @@ export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOpti
|
|||
cropper: {
|
||||
aspectRatio: 1,
|
||||
autoCropArea: 1,
|
||||
viewMode: 0
|
||||
viewMode: 0,
|
||||
},
|
||||
onReady: null,
|
||||
uploader: {
|
||||
|
@ -162,17 +183,17 @@ export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOpti
|
|||
action: "/basic/file/upload",
|
||||
name: "file",
|
||||
headers: {
|
||||
Authorization: "Bearer " + userStore.getToken
|
||||
Authorization: "Bearer " + userStore.getToken,
|
||||
},
|
||||
successHandle(res: any) {
|
||||
return res;
|
||||
}
|
||||
},
|
||||
},
|
||||
buildUrl(key: string) {
|
||||
return `/api/basic/file/download?&key=` + key;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
status: {
|
||||
title: "状态",
|
||||
|
@ -180,24 +201,24 @@ export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOpti
|
|||
dict: dict({
|
||||
data: [
|
||||
{ label: "启用", value: 1, color: "green" },
|
||||
{ label: "禁用", value: 0, color: "red" }
|
||||
]
|
||||
{ label: "禁用", value: 0, color: "red" },
|
||||
],
|
||||
}),
|
||||
column: {
|
||||
align: "center",
|
||||
sorter: true,
|
||||
width: 100
|
||||
}
|
||||
width: 100,
|
||||
},
|
||||
},
|
||||
remark: {
|
||||
title: "备注",
|
||||
type: "text",
|
||||
column: {
|
||||
sorter: true
|
||||
sorter: true,
|
||||
},
|
||||
form: {
|
||||
rules: [{ max: 100, message: "最大100个字符" }]
|
||||
}
|
||||
rules: [{ max: 100, message: "最大100个字符" }],
|
||||
},
|
||||
},
|
||||
roles: {
|
||||
title: "角色",
|
||||
|
@ -205,17 +226,17 @@ export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOpti
|
|||
dict: dict({
|
||||
url: "/sys/authority/role/list",
|
||||
value: "id",
|
||||
label: "name"
|
||||
label: "name",
|
||||
}), // 数据字典
|
||||
form: {
|
||||
component: { mode: "multiple" }
|
||||
component: { mode: "multiple" },
|
||||
},
|
||||
column: {
|
||||
width: 250,
|
||||
sortable: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sortable: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -103,3 +103,4 @@ export async function GetSmsTypeDefine(type: string) {
|
|||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
<!-- </template>-->
|
||||
<div class="sys-settings-body md:p-5">
|
||||
<a-tabs :active-key="activeKey" type="card" class="sys-settings-tabs" @update:active-key="onChange">
|
||||
<a-tab-pane key="" tab="基本设置">
|
||||
<SettingBase v-if="activeKey === ''" />
|
||||
<a-tab-pane key="base" tab="基本设置">
|
||||
<SettingBase v-if="activeKey === 'base'" />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="register" tab="注册设置">
|
||||
<SettingRegister v-if="activeKey === 'register'" />
|
||||
|
@ -14,6 +14,9 @@
|
|||
<a-tab-pane v-if="settingsStore.isComm" key="payment" tab="支付设置">
|
||||
<SettingPayment v-if="activeKey === 'payment'" />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="save" tab="安全设置">
|
||||
<SettingSafe v-if="activeKey === 'save'" />
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
</fs-page>
|
||||
|
@ -23,6 +26,7 @@
|
|||
import SettingBase from "/@/views/sys/settings/tabs/base.vue";
|
||||
import SettingRegister from "/@/views/sys/settings/tabs/register.vue";
|
||||
import SettingPayment from "/@/views/sys/settings/tabs/payment.vue";
|
||||
import SettingSafe from "/@/views/sys/settings/tabs/safe.vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { ref } from "vue";
|
||||
import { useSettingStore } from "/@/store/settings";
|
||||
|
@ -30,11 +34,11 @@ defineOptions({
|
|||
name: "SysSettings",
|
||||
});
|
||||
const settingsStore = useSettingStore();
|
||||
const activeKey = ref("");
|
||||
const activeKey = ref("base");
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
if (route.query.tab) {
|
||||
activeKey.value = (route.query.tab as string) || "";
|
||||
activeKey.value = (route.query.tab as string) || "base";
|
||||
}
|
||||
|
||||
function onChange(value: string) {
|
||||
|
@ -52,7 +56,7 @@ function onChange(value: string) {
|
|||
<style lang="less">
|
||||
.page-sys-settings {
|
||||
.sys-settings-form {
|
||||
width: 500px;
|
||||
width: 600px;
|
||||
max-width: 100%;
|
||||
padding: 20px;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
<template>
|
||||
<div class="sys-settings-form sys-settings-safe">
|
||||
<a-form ref="formRef" :model="formState" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }" autocomplete="off">
|
||||
<div>站点隐藏</div>
|
||||
<a-form-item label="启用站点隐藏" :name="['hidden', 'enabled']" :required="true">
|
||||
<a-switch v-model:checked="formState.hidden.enabled" />
|
||||
<div class="helper">可以在平时关闭站点的可访问性,需要时再打开,增强站点安全性</div>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="formState.hidden.enabled" label="随机地址" :name="['hidden', 'openPath']" :required="true">
|
||||
<a-input-search v-model:value="formState.hidden.openPath" :allow-clear="true" @search="changeOpenPath">
|
||||
<template #enterButton>
|
||||
<fs-icon icon="ion:refresh"></fs-icon>
|
||||
</template>
|
||||
</a-input-search>
|
||||
<div class="helper">站点被隐藏后,需要访问此URL解锁,才能正常访问</div>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="formState.hidden.enabled" label="完整解除隐藏地址" :name="['hidden', 'openPath']" :required="true">
|
||||
<div class="flex"><fs-copyable v-model="openUrl" class="flex-inline"></fs-copyable></div>
|
||||
<div class="helper red">请保存好此地址</div>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="formState.hidden.enabled" label="解除密码" :name="['hidden', 'openPassword']" :required="false">
|
||||
<a-input-password v-model:value="formState.hidden.openPassword" :allow-clear="true" />
|
||||
<div class="helper">解除隐藏时需要输入密码,第一次需要设置密码,填写则重置密码</div>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="formState.hidden.enabled" label="自动隐藏时间" :name="['hidden', 'autoHiddenTimes']" :required="true">
|
||||
<a-input-number v-model:value="formState.hidden.autoHiddenTimes" :allow-clear="true" />
|
||||
<div class="helper">多少分钟内无请求自动隐藏</div>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="formState.hidden.enabled" label="隐藏开放接口" :name="['hidden', 'hiddenOpenApi']" :required="true">
|
||||
<a-switch v-model:checked="formState.hidden.hiddenOpenApi" />
|
||||
<div class="helper">是否隐藏开放接口,是否放开/api/v1开头的接口</div>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="formState.hidden.enabled" label="立即隐藏站点">
|
||||
<loading-button class="ml-1" type="primary" html-type="button" :click="doHiddenImmediate">立即隐藏</loading-button>
|
||||
</a-form-item>
|
||||
<a-form-item label=" " :colon="false" :wrapper-col="{ span: 16 }">
|
||||
<loading-button type="primary" html-type="button" :click="onClick">保存</loading-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="tsx">
|
||||
import { computed, reactive, ref } from "vue";
|
||||
import { merge } from "lodash-es";
|
||||
import { Modal, notification } from "ant-design-vue";
|
||||
import { request } from "/@/api/service";
|
||||
import { util, utils } from "/@/utils";
|
||||
defineOptions({
|
||||
name: "SettingSafe",
|
||||
});
|
||||
|
||||
const api = {
|
||||
async SettingGet() {
|
||||
return await request({
|
||||
url: "/sys/settings/safe/get",
|
||||
method: "post",
|
||||
});
|
||||
},
|
||||
async SettingSave(data: any) {
|
||||
return await request({
|
||||
url: "/sys/settings/safe/save",
|
||||
method: "post",
|
||||
data,
|
||||
});
|
||||
},
|
||||
async HiddenImmediate() {
|
||||
return await request({
|
||||
url: "/sys/settings/safe/hidden",
|
||||
method: "post",
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
const defaultState = {
|
||||
hidden: {
|
||||
enabled: false,
|
||||
autoHiddenTimes: 5,
|
||||
hiddenOpenApi: false,
|
||||
},
|
||||
};
|
||||
const formRef = ref<any>(defaultState);
|
||||
type SiteHidden = {
|
||||
enabled: boolean;
|
||||
openPath?: string;
|
||||
autoHiddenTimes?: number;
|
||||
openPassword?: string;
|
||||
hiddenOpenApi?: boolean;
|
||||
};
|
||||
|
||||
const formState = reactive<
|
||||
Partial<{
|
||||
hidden: SiteHidden;
|
||||
}>
|
||||
>({
|
||||
hidden: { enabled: false },
|
||||
});
|
||||
|
||||
function changeOpenPath() {
|
||||
formState.hidden.openPath = util.randomString(16);
|
||||
}
|
||||
|
||||
async function loadSettings() {
|
||||
const data: any = await api.SettingGet();
|
||||
merge(formState, defaultState, formState, data);
|
||||
if (!formState.hidden.openPath) {
|
||||
changeOpenPath();
|
||||
}
|
||||
}
|
||||
|
||||
loadSettings();
|
||||
|
||||
const openUrl = computed(() => {
|
||||
const url = new URL(window.location.href);
|
||||
url.pathname = `/api/unhidden/${formState.hidden?.openPath || ""}`;
|
||||
//@ts-ignore
|
||||
url.query = undefined;
|
||||
url.hash = "";
|
||||
return url.href;
|
||||
});
|
||||
|
||||
const onClick = async () => {
|
||||
const form = await formRef.value.validateFields();
|
||||
//密码md5
|
||||
// if (form.hidden?.openPassword) {
|
||||
// form.hidden.openPassword = util.hash.md5(form.hidden.openPassword);
|
||||
// }
|
||||
await api.SettingSave(form);
|
||||
await loadSettings();
|
||||
notification.success({
|
||||
message: "保存成功",
|
||||
});
|
||||
};
|
||||
|
||||
async function doHiddenImmediate() {
|
||||
Modal.confirm({
|
||||
title: "确定要立即隐藏站点吗?",
|
||||
content: "隐藏后,将无法访问站点,请谨慎操作",
|
||||
async onOk() {
|
||||
await api.HiddenImmediate();
|
||||
notification.success({
|
||||
message: "站点已隐藏",
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<style lang="less">
|
||||
.sys-settings-base {
|
||||
}
|
||||
</style>
|
|
@ -14,36 +14,19 @@ import DefineOptions from "unplugin-vue-define-options/vite";
|
|||
// 增加环境变量 _
|
||||
process.env.VITE_APP_VERSION = require("./package.json").version;
|
||||
process.env.VITE_APP_BUILD_TIME = require("dayjs")().format("YYYY-M-D HH:mm:ss");
|
||||
|
||||
import { theme } from "ant-design-vue";
|
||||
import * as https from "node:https";
|
||||
const { defaultAlgorithm, defaultSeed } = theme;
|
||||
|
||||
const mapToken = defaultAlgorithm(defaultSeed);
|
||||
|
||||
export default ({ command, mode }) => {
|
||||
console.log("args", command, mode);
|
||||
const env = loadEnv(mode, process.cwd());
|
||||
let devServerFs: any = {};
|
||||
let devAlias: any[] = [];
|
||||
if (mode.startsWith("debug")) {
|
||||
devAlias = [
|
||||
{ find: /@fast-crud\/fast-crud\/dist/, replacement: path.resolve("../../fast-crud/src/") },
|
||||
// { find: /@fast-crud\/fast-crud$/, replacement: path.resolve("../../fast-crud/src/") },
|
||||
{ find: /@fast-crud\/fast-extends\/dist/, replacement: path.resolve("../../fast-extends/src/") },
|
||||
// { find: /@fast-crud\/fast-extends$/, replacement: path.resolve("../../fast-extends/src/") },
|
||||
// { find: /@fast-crud\/ui-antdv$/, replacement: path.resolve("../../ui/ui-antdv/src/") },
|
||||
// { find: /@fast-crud\/ui-interface$/, replacement: path.resolve("../../ui/ui-interface/src/") }
|
||||
{ find: /@fast-crud\/ui-antdv4\/dist/, replacement: path.resolve("../../ui/ui-antdv4/src/") }
|
||||
];
|
||||
devServerFs = {
|
||||
// 这里配置dev启动时读取的项目根目录
|
||||
allow: ["../../../"]
|
||||
};
|
||||
console.log("devAlias", devAlias);
|
||||
}
|
||||
const devServerFs: any = {};
|
||||
const devAlias: any[] = [];
|
||||
const base = "/";
|
||||
// if (mode.startsWith("dev")) {
|
||||
// base = "/dev";
|
||||
// }
|
||||
return {
|
||||
base: "/",
|
||||
base: base,
|
||||
plugins: [
|
||||
DefineOptions(),
|
||||
vueJsx(),
|
||||
|
@ -52,12 +35,12 @@ export default ({ command, mode }) => {
|
|||
inject: {
|
||||
data: {
|
||||
title: env.VITE_APP_TITLE,
|
||||
projectPath: env.VITE_APP_PROJECT_PATH
|
||||
}
|
||||
}
|
||||
projectPath: env.VITE_APP_PROJECT_PATH,
|
||||
},
|
||||
},
|
||||
}),
|
||||
// 压缩build后的代码
|
||||
viteCompression()
|
||||
viteCompression(),
|
||||
//主题色替换
|
||||
//...configThemePlugin(true),
|
||||
// viteThemePlugin({
|
||||
|
@ -71,29 +54,29 @@ export default ({ command, mode }) => {
|
|||
drop: command === "build" ? ["debugger"] : [],
|
||||
pure: ["console.log", "debugger"],
|
||||
jsxFactory: "h",
|
||||
jsxFragment: "Fragment"
|
||||
jsxFragment: "Fragment",
|
||||
},
|
||||
resolve: {
|
||||
alias: [...devAlias, { find: "/@", replacement: path.resolve("./src") }, { find: "/#", replacement: path.resolve("./types") }],
|
||||
dedupe: ["vue"]
|
||||
dedupe: ["vue"],
|
||||
},
|
||||
optimizeDeps: {
|
||||
include: ["ant-design-vue"]
|
||||
include: ["ant-design-vue"],
|
||||
},
|
||||
build: {
|
||||
rollupOptions: {
|
||||
plugins: [visualizer()]
|
||||
}
|
||||
plugins: [visualizer()],
|
||||
},
|
||||
},
|
||||
css: {
|
||||
preprocessorOptions: {
|
||||
less: {
|
||||
// 修改默认主题颜色,配置less变量
|
||||
// modifyVars: generateModifyVars(),
|
||||
javascriptEnabled: true
|
||||
javascriptEnabled: true,
|
||||
// modifyVars: mapToken
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
server: {
|
||||
host: "0.0.0.0",
|
||||
|
@ -105,9 +88,9 @@ export default ({ command, mode }) => {
|
|||
//配套后端 https://github.com/fast-crud/fs-server-js
|
||||
target: "https://127.0.0.1:7002",
|
||||
//忽略证书
|
||||
agent: new https.Agent({ rejectUnauthorized: false })
|
||||
}
|
||||
}
|
||||
}
|
||||
agent: new https.Agent({ rejectUnauthorized: false }),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -19,6 +19,7 @@ import * as libServer from '@certd/lib-server';
|
|||
import * as commercial from '@certd/commercial-core';
|
||||
import * as upload from '@midwayjs/upload';
|
||||
import { setLogger } from '@certd/acme-client';
|
||||
import {HiddenMiddleware} from "./middleware/hidden.js";
|
||||
process.on('uncaughtException', error => {
|
||||
console.error('未捕获的异常:', error);
|
||||
// 在这里可以添加日志记录、发送错误通知等操作
|
||||
|
@ -77,6 +78,8 @@ export class MainConfiguration {
|
|||
this.app.useMiddleware([
|
||||
//统一异常处理
|
||||
GlobalExceptionMiddleware,
|
||||
//站点隐藏
|
||||
HiddenMiddleware,
|
||||
//预览模式限制修改id<1000的数据
|
||||
PreviewMiddleware,
|
||||
//授权处理
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
import {Body, Controller, Get, Inject, Post, Provide} from '@midwayjs/core';
|
||||
import {Constants, NotFoundException, ParamException, SysInstallInfo, SysSettingsService} from '@certd/lib-server';
|
||||
import {utils} from "@certd/basic";
|
||||
import {hiddenStatus, SafeService} from "../../modules/sys/settings/safe-service.js";
|
||||
import {IMidwayKoaContext} from "@midwayjs/koa";
|
||||
|
||||
const unhiddenHtml = `
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>certd解除站点隐藏</title>
|
||||
</head>
|
||||
<body>
|
||||
<div style="margin:50px;width:500px">
|
||||
<h3>解除站点隐藏</h3>
|
||||
<form method="post">
|
||||
请输入解除密码: <input type="password" name="password" /> <button type="submit">确定</button>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
`
|
||||
|
||||
@Provide()
|
||||
@Controller('/api/unhidden')
|
||||
export class HnhiddenController {
|
||||
@Inject()
|
||||
ctx: IMidwayKoaContext;
|
||||
@Inject()
|
||||
safeService: SafeService;
|
||||
@Inject()
|
||||
sysSettingsService: SysSettingsService;
|
||||
|
||||
|
||||
@Post('/:randomPath', {summary: Constants.per.guest})
|
||||
async randomPath(@Body("password") password: any) {
|
||||
await this.checkUnhiddenPath()
|
||||
const hiddenSetting = await this.safeService.getHiddenSetting()
|
||||
if (utils.hash.md5(password) === hiddenSetting.openPassword) {
|
||||
//解锁
|
||||
hiddenStatus.isHidden = false;
|
||||
const setting = await this.sysSettingsService.getSetting<SysInstallInfo>(SysInstallInfo)
|
||||
const bindUrl = setting.bindUrl
|
||||
//解锁成功,跳转回首页,redirect
|
||||
this.ctx.response.redirect(bindUrl || "/");
|
||||
return
|
||||
} else {
|
||||
//密码错误
|
||||
throw new ParamException('解锁密码错误');
|
||||
}
|
||||
}
|
||||
|
||||
@Get('/:randomPath', {summary: Constants.per.guest})
|
||||
async unhiddenGet() {
|
||||
await this.checkUnhiddenPath()
|
||||
this.ctx.response.body = unhiddenHtml
|
||||
}
|
||||
|
||||
async checkUnhiddenPath() {
|
||||
const hiddenSetting = await this.safeService.getHiddenSetting()
|
||||
if (this.ctx.path != `/api/unhidden/${hiddenSetting.openPath}`) {
|
||||
this.ctx.res.statusCode = 404
|
||||
throw new NotFoundException("Page not found")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
import {ALL, Body, Controller, Inject, Post, Provide} from '@midwayjs/core';
|
||||
import {BaseController, SysSafeSetting} from '@certd/lib-server';
|
||||
import {cloneDeep} from 'lodash-es';
|
||||
import {SafeService} from "../../../modules/sys/settings/safe-service.js";
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
@Provide()
|
||||
@Controller('/api/sys/settings/safe')
|
||||
export class SysSettingsController extends BaseController {
|
||||
@Inject()
|
||||
safeService: SafeService;
|
||||
|
||||
|
||||
|
||||
@Post("/get", { summary: "sys:settings:view" })
|
||||
async safeGet() {
|
||||
const res = await this.safeService.getSafeSetting()
|
||||
const clone:SysSafeSetting = cloneDeep(res);
|
||||
delete clone.hidden?.openPassword;
|
||||
return this.ok(clone);
|
||||
}
|
||||
|
||||
@Post("/save", { summary: "sys:settings:edit" })
|
||||
async safeSave(@Body(ALL) body: any) {
|
||||
await this.safeService.saveSafeSetting(body);
|
||||
return this.ok({});
|
||||
}
|
||||
|
||||
/**
|
||||
* 立即隐藏
|
||||
*/
|
||||
@Post("/hidden", { summary: "sys:settings:edit" })
|
||||
async hiddenImmediate() {
|
||||
await this.safeService.hiddenImmediately();
|
||||
return this.ok({});
|
||||
}
|
||||
}
|
|
@ -1,12 +1,19 @@
|
|||
import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core';
|
||||
import { CrudController, SysPrivateSettings, SysPublicSettings, SysSettingsEntity, SysSettingsService } from '@certd/lib-server';
|
||||
import { merge } from 'lodash-es';
|
||||
import { PipelineService } from '../../../modules/pipeline/service/pipeline-service.js';
|
||||
import { UserSettingsService } from '../../../modules/mine/service/user-settings-service.js';
|
||||
import { getEmailSettings } from '../../../modules/sys/settings/fix.js';
|
||||
import { http, logger, simpleNanoId } from '@certd/basic';
|
||||
import { CodeService } from '../../../modules/basic/service/code-service.js';
|
||||
import { SmsServiceFactory } from '../../../modules/basic/sms/factory.js';
|
||||
import {ALL, Body, Controller, Inject, Post, Provide, Query} from '@midwayjs/core';
|
||||
import {
|
||||
CrudController,
|
||||
SysPrivateSettings,
|
||||
SysPublicSettings,
|
||||
SysSafeSetting,
|
||||
SysSettingsEntity,
|
||||
SysSettingsService
|
||||
} from '@certd/lib-server';
|
||||
import {cloneDeep, merge} from 'lodash-es';
|
||||
import {PipelineService} from '../../../modules/pipeline/service/pipeline-service.js';
|
||||
import {UserSettingsService} from '../../../modules/mine/service/user-settings-service.js';
|
||||
import {getEmailSettings} from '../../../modules/sys/settings/fix.js';
|
||||
import {http, logger, simpleNanoId, utils} from '@certd/basic';
|
||||
import {CodeService} from '../../../modules/basic/service/code-service.js';
|
||||
import {SmsServiceFactory} from '../../../modules/basic/sms/factory.js';
|
||||
|
||||
|
||||
/**
|
||||
|
@ -159,4 +166,29 @@ export class SysSettingsController extends CrudController<SysSettingsService> {
|
|||
async getSmsTypeDefine(@Body('type') type: string) {
|
||||
return this.ok(SmsServiceFactory.getDefine(type));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Post("/safe/get", { summary: "sys:settings:view" })
|
||||
async safeGet() {
|
||||
const res = await this.service.getSetting<SysSafeSetting>(SysSafeSetting);
|
||||
const clone:SysSafeSetting = cloneDeep(res);
|
||||
delete clone.hidden?.openPassword;
|
||||
return this.ok(clone);
|
||||
}
|
||||
|
||||
@Post("/safe/save", { summary: "sys:settings:edit" })
|
||||
async safeSave(@Body(ALL) body: any) {
|
||||
if(body.hidden.openPassword){
|
||||
body.hidden.openPassword = utils.hash.md5(body.hidden.openPassword);
|
||||
}
|
||||
const blankSetting = new SysSafeSetting()
|
||||
const setting = await this.service.getSetting<SysSafeSetting>(SysSafeSetting);
|
||||
const newSetting = merge(blankSetting,cloneDeep(setting), body);
|
||||
if(newSetting.hidden?.enabled && !newSetting.hidden?.openPassword){
|
||||
throw new Error("首次设置需要填写解锁密码")
|
||||
}
|
||||
await this.service.saveSetting(blankSetting);
|
||||
return this.ok({});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
import {Inject, Provide} from '@midwayjs/core';
|
||||
import {IMidwayKoaContext, IWebMiddleware, NextFunction} from '@midwayjs/koa';
|
||||
import {hiddenStatus, SafeService} from "../modules/sys/settings/safe-service.js";
|
||||
import {SiteOffException} from "@certd/lib-server";
|
||||
|
||||
|
||||
/**
|
||||
* 隐藏环境
|
||||
*/
|
||||
@Provide()
|
||||
export class HiddenMiddleware implements IWebMiddleware {
|
||||
@Inject()
|
||||
hiddenService: SafeService;
|
||||
|
||||
resolve() {
|
||||
return async (ctx: IMidwayKoaContext, next: NextFunction) => {
|
||||
|
||||
async function pass() {
|
||||
hiddenStatus.updateRequestTime()
|
||||
await next();
|
||||
}
|
||||
|
||||
const hiddenSetting = await this.hiddenService.getHiddenSetting();
|
||||
if (!hiddenSetting || !hiddenSetting?.enabled) {
|
||||
//未开启站点隐藏,直接通过
|
||||
return await pass()
|
||||
}
|
||||
|
||||
const req = ctx.request;
|
||||
if (hiddenSetting.hiddenOpenApi === false && req.url.startsWith(`/api/v1/`) ) {
|
||||
//不隐藏开放接口
|
||||
await next();
|
||||
return
|
||||
}
|
||||
|
||||
//判断当前是否是隐藏状态
|
||||
if (!hiddenStatus.isHidden) {
|
||||
return await pass()
|
||||
}
|
||||
|
||||
//判断是否有解锁文件,如果有就返回true并删除文件
|
||||
if (hiddenStatus.hasUnHiddenFile()) {
|
||||
//临时修改为未隐藏
|
||||
hiddenStatus.isHidden = false;
|
||||
return await pass()
|
||||
}
|
||||
|
||||
if (req.url === `/api/unhidden/${hiddenSetting.openPath}`) {
|
||||
return await pass();
|
||||
}
|
||||
throw new SiteOffException('此站点已关闭');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ import { UserService } from '../sys/authority/service/user-service.js';
|
|||
import { PlusService, SysInstallInfo, SysPrivateSettings, SysSettingsService } from '@certd/lib-server';
|
||||
import { nanoid } from 'nanoid';
|
||||
import crypto from 'crypto';
|
||||
import {SafeService} from "../sys/settings/safe-service.js";
|
||||
|
||||
@Autoload()
|
||||
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||
|
@ -18,6 +19,8 @@ export class AutoAInitSite {
|
|||
sysSettingsService: SysSettingsService;
|
||||
@Inject()
|
||||
plusService: PlusService;
|
||||
@Inject()
|
||||
safeService: SafeService;
|
||||
|
||||
@Init()
|
||||
async init() {
|
||||
|
@ -57,6 +60,8 @@ export class AutoAInitSite {
|
|||
logger.error('授权许可验证失败', e);
|
||||
}
|
||||
|
||||
//加载站点隐藏配置
|
||||
await this.safeService.reloadHiddenStatus(true)
|
||||
logger.info('初始化站点完成');
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
import {Inject, Provide, Scope, ScopeEnum} from '@midwayjs/core';
|
||||
import {SiteHidden, SysSafeSetting, SysSettingsService} from "@certd/lib-server";
|
||||
import fs from "fs";
|
||||
import {logger, utils} from "@certd/basic";
|
||||
import {cloneDeep, merge} from "lodash-es";
|
||||
|
||||
|
||||
export class HiddenStatus {
|
||||
|
||||
|
||||
isHidden = false;
|
||||
lastRequestTime = 0;
|
||||
intervalId: any = null;
|
||||
|
||||
hasUnHiddenFile() {
|
||||
if (fs.existsSync(`./data/.unhidden`)) {
|
||||
fs.unlinkSync(`./data/.unhidden`)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
updateRequestTime() {
|
||||
this.lastRequestTime = Date.now();
|
||||
}
|
||||
|
||||
startCheck(autoHiddenTimes = 5) {
|
||||
this.stopCheck()
|
||||
this.intervalId = setInterval(() => {
|
||||
//默认5分钟后自动隐藏
|
||||
if (!this.isHidden && Date.now() - this.lastRequestTime > 1000 * 60 * autoHiddenTimes) {
|
||||
this.isHidden = true;
|
||||
}
|
||||
}, 1000 * 60)
|
||||
}
|
||||
|
||||
stopCheck() {
|
||||
if (this.intervalId) {
|
||||
clearInterval(this.intervalId)
|
||||
this.intervalId = null
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const hiddenStatus = new HiddenStatus();
|
||||
|
||||
|
||||
@Provide('safeService')
|
||||
@Scope(ScopeEnum.Request, {allowDowngrade: true})
|
||||
export class SafeService {
|
||||
|
||||
@Inject()
|
||||
sysSettingsService: SysSettingsService;
|
||||
|
||||
|
||||
async reloadHiddenStatus(immediate = false) {
|
||||
const hidden = await this.getHiddenSetting()
|
||||
if (hidden.enabled) {
|
||||
logger.error("启动站点隐藏");
|
||||
hiddenStatus.isHidden = false
|
||||
if (immediate) {
|
||||
hiddenStatus.isHidden = true;
|
||||
}
|
||||
const autoHiddenTimes = hidden.autoHiddenTimes || 5;
|
||||
hiddenStatus.startCheck(autoHiddenTimes);
|
||||
} else {
|
||||
logger.error("关闭站点隐藏");
|
||||
hiddenStatus.isHidden = false;
|
||||
hiddenStatus.stopCheck()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async getHiddenSetting(): Promise<SiteHidden> {
|
||||
const safeSetting = await this.getSafeSetting()
|
||||
return safeSetting.hidden || {enabled: false}
|
||||
}
|
||||
|
||||
async getSafeSetting() {
|
||||
return await this.sysSettingsService.getSetting<SysSafeSetting>(SysSafeSetting)
|
||||
}
|
||||
|
||||
async hiddenImmediately() {
|
||||
return hiddenStatus.isHidden = true
|
||||
}
|
||||
|
||||
async saveSafeSetting(body: SysSafeSetting) {
|
||||
|
||||
// 更新hidden配置
|
||||
if (body.hidden.openPassword) {
|
||||
body.hidden.openPassword = utils.hash.md5(body.hidden.openPassword);
|
||||
}
|
||||
const blankSetting = new SysSafeSetting()
|
||||
const setting = await this.getSafeSetting()
|
||||
const newSetting = merge(blankSetting, cloneDeep(setting), body);
|
||||
if (newSetting.hidden?.enabled && !newSetting.hidden?.openPassword) {
|
||||
throw new Error("首次设置需要填写解锁密码")
|
||||
}
|
||||
|
||||
if(isNaN(newSetting.hidden.autoHiddenTimes) || newSetting.hidden.autoHiddenTimes < 1){
|
||||
newSetting.hidden.autoHiddenTimes = 1
|
||||
}
|
||||
|
||||
await this.sysSettingsService.saveSetting(newSetting);
|
||||
|
||||
await this.reloadHiddenStatus(false)
|
||||
|
||||
}
|
||||
}
|
|
@ -128,11 +128,11 @@ export class DeployCertToTencentAll extends AbstractTaskPlugin {
|
|||
});
|
||||
|
||||
let certId:string = null
|
||||
if (typeof certId === 'string') {
|
||||
certId = this.tencentCertId as string;
|
||||
} else {
|
||||
if (typeof certId === 'object') {
|
||||
//上传
|
||||
certId = await this.uploadToTencent(access,this.tencentCertId as CertInfo);
|
||||
} else {
|
||||
certId = this.tencentCertId as string;
|
||||
}
|
||||
|
||||
const params = {
|
||||
|
|
173
pnpm-lock.yaml
173
pnpm-lock.yaml
|
@ -46,7 +46,7 @@ importers:
|
|||
packages/core/acme-client:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.33.2
|
||||
version: link:../basic
|
||||
'@peculiar/x509':
|
||||
specifier: ^1.11.0
|
||||
|
@ -204,11 +204,11 @@ importers:
|
|||
packages/core/pipeline:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.33.2
|
||||
version: link:../basic
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.33.0
|
||||
version: link:../../pro/plus-core
|
||||
specifier: ^1.33.2
|
||||
version: 1.33.2
|
||||
dayjs:
|
||||
specifier: ^1.11.7
|
||||
version: 1.11.13
|
||||
|
@ -412,7 +412,7 @@ importers:
|
|||
packages/libs/lib-k8s:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.33.2
|
||||
version: link:../../core/basic
|
||||
'@kubernetes/client-node':
|
||||
specifier: 0.21.0
|
||||
|
@ -452,17 +452,17 @@ importers:
|
|||
packages/libs/lib-server:
|
||||
dependencies:
|
||||
'@certd/acme-client':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.33.2
|
||||
version: link:../../core/acme-client
|
||||
'@certd/basic':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.33.2
|
||||
version: link:../../core/basic
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.33.2
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.33.0
|
||||
version: link:../../pro/plus-core
|
||||
specifier: ^1.33.2
|
||||
version: 1.33.2
|
||||
'@midwayjs/cache':
|
||||
specifier: ~3.14.0
|
||||
version: 3.14.0
|
||||
|
@ -604,16 +604,16 @@ importers:
|
|||
packages/plugins/plugin-cert:
|
||||
dependencies:
|
||||
'@certd/acme-client':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.33.2
|
||||
version: link:../../core/acme-client
|
||||
'@certd/basic':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.33.2
|
||||
version: link:../../core/basic
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.33.2
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plugin-lib':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.33.2
|
||||
version: link:../plugin-lib
|
||||
'@google-cloud/publicca':
|
||||
specifier: ^1.3.0
|
||||
|
@ -680,10 +680,10 @@ importers:
|
|||
specifier: ^1.7.10
|
||||
version: 1.8.0
|
||||
'@certd/basic':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.33.2
|
||||
version: link:../../core/basic
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.33.2
|
||||
version: link:../../core/pipeline
|
||||
'@kubernetes/client-node':
|
||||
specifier: 0.21.0
|
||||
|
@ -771,19 +771,19 @@ importers:
|
|||
packages/pro/commercial-core:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.32.0
|
||||
version: link:../../core/basic
|
||||
'@certd/lib-server':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.32.0
|
||||
version: link:../../libs/lib-server
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.32.0
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plugin-plus':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.32.0
|
||||
version: link:../plugin-plus
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.32.0
|
||||
version: link:../plus-core
|
||||
'@midwayjs/core':
|
||||
specifier: ~3.20.3
|
||||
|
@ -868,22 +868,22 @@ importers:
|
|||
specifier: ^1.0.2
|
||||
version: 1.0.2
|
||||
'@certd/basic':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.32.0
|
||||
version: link:../../core/basic
|
||||
'@certd/lib-k8s':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.32.0
|
||||
version: link:../../libs/lib-k8s
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.32.0
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plugin-cert':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.32.0
|
||||
version: link:../../plugins/plugin-cert
|
||||
'@certd/plugin-lib':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.32.0
|
||||
version: link:../../plugins/plugin-lib
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.32.0
|
||||
version: link:../plus-core
|
||||
ali-oss:
|
||||
specifier: ^6.21.0
|
||||
|
@ -980,7 +980,7 @@ importers:
|
|||
packages/pro/plus-core:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.32.0
|
||||
version: link:../../core/basic
|
||||
dayjs:
|
||||
specifier: ^1.11.7
|
||||
|
@ -1223,6 +1223,9 @@ importers:
|
|||
sortablejs:
|
||||
specifier: ^1.15.3
|
||||
version: 1.15.6
|
||||
spark-md5:
|
||||
specifier: ^3.0.2
|
||||
version: 3.0.2
|
||||
tailwind-merge:
|
||||
specifier: ^3.0.2
|
||||
version: 3.0.2
|
||||
|
@ -1267,10 +1270,10 @@ importers:
|
|||
version: 0.1.3(zod@3.24.2)
|
||||
devDependencies:
|
||||
'@certd/lib-iframe':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.33.2
|
||||
version: link:../../libs/lib-iframe
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.33.2
|
||||
version: link:../../core/pipeline
|
||||
'@rollup/plugin-commonjs':
|
||||
specifier: ^25.0.7
|
||||
|
@ -1450,44 +1453,44 @@ importers:
|
|||
specifier: ^3.705.0
|
||||
version: 3.758.0(aws-crt@1.25.3)
|
||||
'@certd/acme-client':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.33.2
|
||||
version: link:../../core/acme-client
|
||||
'@certd/basic':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.33.2
|
||||
version: link:../../core/basic
|
||||
'@certd/commercial-core':
|
||||
specifier: ^1.33.0
|
||||
version: link:../../pro/commercial-core
|
||||
specifier: ^1.33.2
|
||||
version: 1.33.2(better-sqlite3@11.8.1)(encoding@0.1.13)(mysql2@3.14.0)(pg@8.13.3)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@18.19.80)(typescript@5.8.2))
|
||||
'@certd/jdcloud':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.33.2
|
||||
version: link:../../libs/lib-jdcloud
|
||||
'@certd/lib-huawei':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.33.2
|
||||
version: link:../../libs/lib-huawei
|
||||
'@certd/lib-k8s':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.33.2
|
||||
version: link:../../libs/lib-k8s
|
||||
'@certd/lib-server':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.33.2
|
||||
version: link:../../libs/lib-server
|
||||
'@certd/midway-flyway-js':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.33.2
|
||||
version: link:../../libs/midway-flyway-js
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.33.2
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plugin-cert':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.33.2
|
||||
version: link:../../plugins/plugin-cert
|
||||
'@certd/plugin-lib':
|
||||
specifier: ^1.33.0
|
||||
specifier: ^1.33.2
|
||||
version: link:../../plugins/plugin-lib
|
||||
'@certd/plugin-plus':
|
||||
specifier: ^1.33.0
|
||||
version: link:../../pro/plugin-plus
|
||||
specifier: ^1.33.2
|
||||
version: 1.33.2(encoding@0.1.13)
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.33.0
|
||||
version: link:../../pro/plus-core
|
||||
specifier: ^1.33.2
|
||||
version: 1.33.2
|
||||
'@corsinvest/cv4pve-api-javascript':
|
||||
specifier: ^8.3.0
|
||||
version: 8.3.0
|
||||
|
@ -2617,6 +2620,15 @@ packages:
|
|||
'@better-scroll/zoom@2.5.1':
|
||||
resolution: {integrity: sha512-aGvFY5ooeZWS4RcxQLD+pGLpQHQxpPy0sMZV3yadcd2QK53PK9gS4Dp+BYfRv8lZ4/P2LoNEhr6Wq1DN6+uPlA==}
|
||||
|
||||
'@certd/commercial-core@1.33.2':
|
||||
resolution: {integrity: sha512-LTRvwRAkMEU+knG+/eA8QbyK3EE2Z2eyn4763ILadCY/qHLAWqxg7NUD+fwsuAoByvsr3l5qLPPOF73p5s1iEA==}
|
||||
|
||||
'@certd/plugin-plus@1.33.2':
|
||||
resolution: {integrity: sha512-x8qdJ1qtYfqVNBQ3uWJuFVYUHHnteoaH/3vnYKjgAnEAcosruZAz8h5RwwOjDhR+Vsdda/sSRdjlTCVDLidHZg==}
|
||||
|
||||
'@certd/plus-core@1.33.2':
|
||||
resolution: {integrity: sha512-CsD+/P3Ycne3KzxrZAkFXGpCO9ZQNY4p28WAA2XfKQ6sLIYLuuDBP18V/E7EygfJEZ/c9KJWMkYgx/4wGGvb6w==}
|
||||
|
||||
'@colors/colors@1.5.0':
|
||||
resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==}
|
||||
engines: {node: '>=0.1.90'}
|
||||
|
@ -14791,6 +14803,75 @@ snapshots:
|
|||
dependencies:
|
||||
'@better-scroll/core': 2.5.1
|
||||
|
||||
'@certd/commercial-core@1.33.2(better-sqlite3@11.8.1)(encoding@0.1.13)(mysql2@3.14.0)(pg@8.13.3)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@18.19.80)(typescript@5.8.2))':
|
||||
dependencies:
|
||||
'@certd/basic': link:packages/core/basic
|
||||
'@certd/lib-server': link:packages/libs/lib-server
|
||||
'@certd/pipeline': link:packages/core/pipeline
|
||||
'@certd/plugin-plus': 1.33.2(encoding@0.1.13)
|
||||
'@certd/plus-core': 1.33.2
|
||||
'@midwayjs/core': 3.20.3
|
||||
'@midwayjs/koa': 3.20.3
|
||||
'@midwayjs/logger': 3.4.2
|
||||
'@midwayjs/typeorm': 3.20.3
|
||||
alipay-sdk: 4.13.0
|
||||
dayjs: 1.11.13
|
||||
typeorm: 0.3.21(better-sqlite3@11.8.1)(mysql2@3.14.0)(pg@8.13.3)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@18.19.80)(typescript@5.8.2))
|
||||
wechatpay-node-v3: 2.2.1
|
||||
transitivePeerDependencies:
|
||||
- '@google-cloud/spanner'
|
||||
- '@sap/hana-client'
|
||||
- better-sqlite3
|
||||
- encoding
|
||||
- hdb-pool
|
||||
- ioredis
|
||||
- mongodb
|
||||
- mssql
|
||||
- mysql2
|
||||
- oracledb
|
||||
- pg
|
||||
- pg-native
|
||||
- pg-query-stream
|
||||
- proxy-agent
|
||||
- redis
|
||||
- reflect-metadata
|
||||
- sql.js
|
||||
- sqlite3
|
||||
- supports-color
|
||||
- ts-node
|
||||
- typeorm-aurora-data-api-driver
|
||||
|
||||
'@certd/plugin-plus@1.33.2(encoding@0.1.13)':
|
||||
dependencies:
|
||||
'@alicloud/pop-core': 1.8.0
|
||||
'@baiducloud/sdk': 1.0.2
|
||||
'@certd/basic': link:packages/core/basic
|
||||
'@certd/lib-k8s': link:packages/libs/lib-k8s
|
||||
'@certd/pipeline': link:packages/core/pipeline
|
||||
'@certd/plugin-cert': link:packages/plugins/plugin-cert
|
||||
'@certd/plugin-lib': link:packages/plugins/plugin-lib
|
||||
'@certd/plus-core': 1.33.2
|
||||
ali-oss: 6.22.0
|
||||
baidu-aip-sdk: 4.16.16
|
||||
basic-ftp: 5.0.5
|
||||
cos-nodejs-sdk-v5: 2.14.6
|
||||
crypto-js: 4.2.0
|
||||
dayjs: 1.11.13
|
||||
form-data: 4.0.2
|
||||
https-proxy-agent: 7.0.6
|
||||
jsencrypt: 3.3.2
|
||||
qiniu: 7.14.0
|
||||
tencentcloud-sdk-nodejs: 4.0.1045(encoding@0.1.13)
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
- proxy-agent
|
||||
- supports-color
|
||||
|
||||
'@certd/plus-core@1.33.2':
|
||||
dependencies:
|
||||
'@certd/basic': link:packages/core/basic
|
||||
dayjs: 1.11.13
|
||||
|
||||
'@colors/colors@1.5.0':
|
||||
optional: true
|
||||
|
||||
|
|
Loading…
Reference in New Issue