mirror of
https://github.com/certd/certd.git
synced 2026-05-14 20:17:32 +08:00
Merge branch 'v2-dev' of https://github.com/certd/certd into v2-dev
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-huawei",
|
||||
"private": false,
|
||||
"version": "1.39.15",
|
||||
"version": "1.39.16",
|
||||
"main": "./dist/bundle.js",
|
||||
"module": "./dist/bundle.js",
|
||||
"types": "./dist/d/index.d.ts",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-iframe",
|
||||
"private": false,
|
||||
"version": "1.39.15",
|
||||
"version": "1.39.16",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/jdcloud",
|
||||
"version": "1.39.15",
|
||||
"version": "1.39.16",
|
||||
"description": "jdcloud openApi sdk",
|
||||
"main": "./dist/bundle.js",
|
||||
"module": "./dist/bundle.js",
|
||||
|
||||
@@ -64,6 +64,7 @@ export class SysPublicSettings extends BaseSettings {
|
||||
type: string;
|
||||
title: string;
|
||||
addonId: number;
|
||||
icon?: string;
|
||||
}> = {};
|
||||
|
||||
notice?: string;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/midway-flyway-js",
|
||||
"version": "1.39.15",
|
||||
"version": "1.39.16",
|
||||
"description": "midway with flyway, sql upgrade way ",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
"zod-defaults": "^0.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@certd/lib-iframe": "^1.39.15",
|
||||
"@certd/lib-iframe": "^1.39.16",
|
||||
"@certd/pipeline": "^1.39.16",
|
||||
"@rollup/plugin-commonjs": "^25.0.7",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
|
||||
@@ -85,6 +85,7 @@ export type SysPublicSetting = {
|
||||
type: string;
|
||||
title: string;
|
||||
addonId: number;
|
||||
icon?: string;
|
||||
}
|
||||
>;
|
||||
// 系统通知
|
||||
|
||||
@@ -38,6 +38,9 @@ export const useUserStore = defineStore({
|
||||
getToken(): string {
|
||||
return this.token || LocalStorage.get(TOKEN_KEY);
|
||||
},
|
||||
isLogined(): boolean {
|
||||
return !!this.getToken;
|
||||
},
|
||||
isAdmin(): boolean {
|
||||
return this.getUserInfo.roleIds?.includes(1) || this.getUserInfo.id === 1;
|
||||
},
|
||||
|
||||
@@ -68,20 +68,23 @@ export async function GetOauthProviders() {
|
||||
});
|
||||
}
|
||||
|
||||
export async function UnbindOauth(type: string) {
|
||||
export async function UnbindOauth(type: string, subtype?: string) {
|
||||
return await request({
|
||||
url: "/oauth/unbind",
|
||||
method: "POST",
|
||||
data: { type },
|
||||
data: {
|
||||
type: subtype ? `${type}:${subtype}` : type,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function OauthBoundUrl(type: string) {
|
||||
export async function OauthBoundUrl(type: string, subtype?: string) {
|
||||
return await request({
|
||||
url: "/oauth/login",
|
||||
method: "POST",
|
||||
data: {
|
||||
type,
|
||||
subtype,
|
||||
forType: "bind",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -78,11 +78,11 @@
|
||||
<a-tag v-else color="red" class="bound-tag1">未绑定</a-tag>
|
||||
</span>
|
||||
</div>
|
||||
<a-button v-if="item.bound" type="primary" danger class="action-btn" @click="unbind(item.name)">
|
||||
<a-button v-if="item.bound" type="primary" danger class="action-btn" @click="unbind(item)">
|
||||
<template #icon><fs-icon icon="ion:unlink-outline" /></template>
|
||||
解绑
|
||||
</a-button>
|
||||
<a-button v-else type="primary" class="action-btn" @click="bind(item.name)">
|
||||
<a-button v-else type="primary" class="action-btn" @click="bind(item)">
|
||||
<template #icon><fs-icon icon="ion:link-outline" /></template>
|
||||
绑定
|
||||
</a-button>
|
||||
@@ -214,7 +214,7 @@ async function loadOauthProviders() {
|
||||
|
||||
const computedOauthBounds = computed(() => {
|
||||
const list = oauthProviders.value.map(item => {
|
||||
const bound = oauthBounds.value.find(bound => bound.type === item.name);
|
||||
const bound = oauthBounds.value.find(bound => bound.type === buildOauthBoundType(item));
|
||||
return {
|
||||
...item,
|
||||
bound,
|
||||
@@ -223,20 +223,24 @@ const computedOauthBounds = computed(() => {
|
||||
return list;
|
||||
});
|
||||
|
||||
async function unbind(type: string) {
|
||||
function buildOauthBoundType(item: any) {
|
||||
return item.subtype ? `${item.name}:${item.subtype}` : item.name;
|
||||
}
|
||||
|
||||
async function unbind(item: any) {
|
||||
Modal.confirm({
|
||||
title: "确认解绑吗?",
|
||||
okText: "确认",
|
||||
okType: "danger",
|
||||
onOk: async () => {
|
||||
await api.UnbindOauth(type);
|
||||
await api.UnbindOauth(item.name, item.subtype);
|
||||
await loadOauthBounds();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function bind(type: string) {
|
||||
const res = await api.OauthBoundUrl(type);
|
||||
async function bind(item: any) {
|
||||
const res = await api.OauthBoundUrl(item.name, item.subtype);
|
||||
const loginUrl = res.loginUrl;
|
||||
window.location.href = loginUrl;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { request } from "/src/api/service";
|
||||
|
||||
const apiPrefix = "/oauth";
|
||||
|
||||
export async function OauthLogin(type: string, forType?: string, from?: string) {
|
||||
export async function OauthLogin(type: string, forType?: string, from?: string, subtype?: string) {
|
||||
return await request({
|
||||
url: apiPrefix + `/login`,
|
||||
method: "post",
|
||||
@@ -10,6 +10,7 @@ export async function OauthLogin(type: string, forType?: string, from?: string)
|
||||
type,
|
||||
forType: forType || "login",
|
||||
from: from || "web",
|
||||
subtype,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
<div>第三方({{ oauthType }})登录成功,您还未绑定账号,请选择</div>
|
||||
|
||||
<div class="mt-10">
|
||||
<a-button class="w-full mt-10" type="primary" @click="goBindUser">绑定已有账号</a-button>
|
||||
<a-button v-if="settingStore.sysPublic.registerEnabled" class="w-full mt-10" type="primary" @click="autoRegister">创建新账号</a-button>
|
||||
<a-button v-if="!userStore.isLogined" class="w-full mt-10" type="primary" @click="goBindUser">绑定已有账号</a-button>
|
||||
<a-button v-else class="w-full mt-10" type="primary" @click="doBindCurrent">绑定当前登录账号({{ userStore.getUserInfo.username }} - {{ userStore.getUserInfo.nickName }})</a-button>
|
||||
<a-button v-if="settingStore.sysPublic.registerEnabled" class="w-full mt-10" type="primary" @click="autoRegister">创建新账号绑定</a-button>
|
||||
</div>
|
||||
|
||||
<div class="w-full mt-10">
|
||||
@@ -63,6 +64,15 @@ async function handleOauthToken() {
|
||||
}
|
||||
}
|
||||
|
||||
async function doBindCurrent() {
|
||||
await api.BindUser(validationCode);
|
||||
notification.success({
|
||||
message: "绑定成功",
|
||||
});
|
||||
//跳转到首页
|
||||
router.replace("/certd/mine/user-profile");
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
if (error.value) {
|
||||
return;
|
||||
@@ -70,12 +80,7 @@ onMounted(async () => {
|
||||
|
||||
if (forType === "bind") {
|
||||
//从用户中心页面,进行第三方账号的绑定
|
||||
await api.BindUser(validationCode);
|
||||
notification.success({
|
||||
message: "绑定成功",
|
||||
});
|
||||
//跳转到首页
|
||||
router.replace("/certd/mine/user-profile");
|
||||
await doBindCurrent();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -98,7 +103,7 @@ async function autoRegister() {
|
||||
//登录成功
|
||||
userStore.onLoginSuccess(res);
|
||||
//跳转到首页
|
||||
router.replace("/");
|
||||
router.replace("/index");
|
||||
}
|
||||
</script>
|
||||
<style lang="less">
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
</div>
|
||||
<div class="flex justify-center items-center gap-4 flex-wrap md:flex-nowrap">
|
||||
<passkey-login></passkey-login>
|
||||
<template v-for="item in oauthProviderList" :key="item.type">
|
||||
<div v-if="item.addonId" class="oauth-icon-button pointer" @click="goOauthLogin(item.name)">
|
||||
<template v-for="item in oauthProviderList" :key="buildProviderKey(item)">
|
||||
<div v-if="item.addonId" class="oauth-icon-button pointer" @click="goOauthLogin(item)">
|
||||
<div><fs-icon :icon="item.icon" class="text-blue-600 text-40" /></div>
|
||||
<div class="ellipsis title" :title="item.addonTitle || item.title">{{ item.addonTitle || item.title }}</div>
|
||||
</div>
|
||||
@@ -22,7 +22,17 @@ import { useSettingStore } from "/@/store/settings";
|
||||
import { useRoute } from "vue-router";
|
||||
import PasskeyLogin from "../login/passkey-login.vue";
|
||||
|
||||
const oauthProviderList = ref([]);
|
||||
type OauthProviderItem = {
|
||||
name: string;
|
||||
type?: string;
|
||||
subtype?: string;
|
||||
title: string;
|
||||
addonTitle?: string;
|
||||
icon: string;
|
||||
addonId?: number;
|
||||
};
|
||||
|
||||
const oauthProviderList = ref<OauthProviderItem[]>([]);
|
||||
const props = defineProps<{
|
||||
oauthOnly?: boolean;
|
||||
}>();
|
||||
@@ -42,15 +52,19 @@ onMounted(async () => {
|
||||
if (settingStore.sysPublic.oauthAutoRedirect && queryOauthOnly !== "false") {
|
||||
const firstOauth = oauthProviderList.value.find(item => item.addonId > 0);
|
||||
if (firstOauth) {
|
||||
goOauthLogin(firstOauth.name);
|
||||
goOauthLogin(firstOauth);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
async function goOauthLogin(type: string) {
|
||||
function buildProviderKey(item: OauthProviderItem) {
|
||||
return `${item.name}:${item.subtype || ""}`;
|
||||
}
|
||||
|
||||
async function goOauthLogin(item: OauthProviderItem) {
|
||||
//获取第三方登录URL
|
||||
const from = "web";
|
||||
const res = await api.OauthLogin(type, from);
|
||||
const res = await api.OauthLogin(item.name, "login", from, item.subtype);
|
||||
const loginUrl = res.loginUrl;
|
||||
window.location.href = loginUrl;
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ export async function GetSmsTypeDefine(type: string) {
|
||||
|
||||
export async function GetOauthProviders() {
|
||||
return await request({
|
||||
url: "/oauth/providers",
|
||||
url: apiPrefix + "/oauth/providers",
|
||||
method: "post",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -109,6 +109,7 @@ const formState = reactive<Partial<SysSettings>>({
|
||||
const oauthProviders = ref([]);
|
||||
async function loadOauthProviders() {
|
||||
oauthProviders.value = await api.GetOauthProviders();
|
||||
mergeOauthProviderSettings();
|
||||
}
|
||||
|
||||
const bindDomain = computed(() => {
|
||||
@@ -164,6 +165,16 @@ const onFinish = async (form: any) => {
|
||||
function buildCallbackUrl(type: string) {
|
||||
return `${window.location.origin}/api/oauth/callback/${type}`;
|
||||
}
|
||||
|
||||
function mergeOauthProviderSettings() {
|
||||
const savedProviders = formState.public?.oauthProviders || {};
|
||||
for (const item of oauthProviders.value) {
|
||||
const saved = savedProviders[item.name];
|
||||
if (saved) {
|
||||
item.addonId = saved.addonId;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less">
|
||||
.sys-settings-oauth {
|
||||
|
||||
@@ -14,55 +14,54 @@ input:
|
||||
loginType:
|
||||
title: 登录类型
|
||||
component:
|
||||
name: a-auto-complete
|
||||
name: a-select
|
||||
vModel: value
|
||||
mode: tags
|
||||
multiple: true
|
||||
options:
|
||||
- label: QQ
|
||||
value: qq
|
||||
icon: logos:tencent-qq
|
||||
- label: 微信
|
||||
value: wx
|
||||
icon: logos:wechat-icon
|
||||
- label: 支付宝
|
||||
value: alipay
|
||||
icon: logos:alipay
|
||||
- label: 微博
|
||||
value: sina
|
||||
icon: logos:sina-weibo
|
||||
- label: 百度
|
||||
value: baidu
|
||||
icon: logos:baidu
|
||||
- label: 华为
|
||||
value: huawei
|
||||
icon: simple-icons:huawei:#ff0000
|
||||
- label: 小米
|
||||
value: xiaomi
|
||||
icon: logos:xiaomi-icon
|
||||
- label: 谷歌
|
||||
value: google
|
||||
icon: logos:google-icon
|
||||
- label: 微软
|
||||
value: microsoft
|
||||
icon: logos:microsoft-icon
|
||||
- label: Facebook
|
||||
value: facebook
|
||||
icon: logos:facebook
|
||||
- label: Twitter
|
||||
value: twitter
|
||||
icon: logos:twitter
|
||||
- label: 钉钉
|
||||
value: dingtalk
|
||||
icon: logos:dingtalk
|
||||
- label: Gitee
|
||||
value: gitee
|
||||
icon: simple-icons:gitee:#c71d23
|
||||
- label: Github
|
||||
value: github
|
||||
icon: logos:github-icon
|
||||
required: true
|
||||
icon:
|
||||
title: 自定义图标
|
||||
component:
|
||||
name: fs-icon-selector
|
||||
vModel: modelValue
|
||||
iconSets:
|
||||
- streamline-logos
|
||||
- logos
|
||||
- fa-brands
|
||||
- fa-solid
|
||||
- fa-regular
|
||||
- carbon
|
||||
- ion
|
||||
- ant-design
|
||||
- mdi
|
||||
- twemoji
|
||||
- svg-spinners
|
||||
required: false
|
||||
appId:
|
||||
title: AppId
|
||||
helper: 彩虹聚合登录->应用列表->创建应用 获取
|
||||
|
||||
@@ -57,11 +57,11 @@
|
||||
"@certd/basic": "^1.39.16",
|
||||
"@certd/commercial-core": "^1.39.16",
|
||||
"@certd/cv4pve-api-javascript": "^8.4.2",
|
||||
"@certd/jdcloud": "^1.39.15",
|
||||
"@certd/lib-huawei": "^1.39.15",
|
||||
"@certd/jdcloud": "^1.39.16",
|
||||
"@certd/lib-huawei": "^1.39.16",
|
||||
"@certd/lib-k8s": "^1.39.16",
|
||||
"@certd/lib-server": "^1.39.16",
|
||||
"@certd/midway-flyway-js": "^1.39.15",
|
||||
"@certd/midway-flyway-js": "^1.39.16",
|
||||
"@certd/pipeline": "^1.39.16",
|
||||
"@certd/plugin-cert": "^1.39.16",
|
||||
"@certd/plugin-lib": "^1.39.16",
|
||||
|
||||
@@ -11,6 +11,24 @@ import { UserEntity } from "../../../modules/sys/authority/entity/user.js";
|
||||
import { UserService } from "../../../modules/sys/authority/service/user-service.js";
|
||||
import { IOauthProvider } from "../../../plugins/plugin-oauth/api.js";
|
||||
|
||||
type OauthProviderSetting = {
|
||||
type: string;
|
||||
title: string;
|
||||
icon?: string;
|
||||
addonId: number;
|
||||
types?: OauthProviderType[];
|
||||
};
|
||||
|
||||
type OauthProviderType = {
|
||||
type: string;
|
||||
name: string;
|
||||
icon?: string;
|
||||
};
|
||||
|
||||
function getOauthBoundType(type: string, subtype?: string) {
|
||||
return subtype ? `${type}:${subtype}` : type;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
@Provide()
|
||||
@@ -41,7 +59,7 @@ export class ConnectController extends BaseController {
|
||||
if (!publicSettings?.oauthEnabled) {
|
||||
throw new Error("OAuth功能未启用");
|
||||
}
|
||||
const setting = publicSettings?.oauthProviders?.[type || ""]
|
||||
const setting = publicSettings?.oauthProviders?.[type || ""] as OauthProviderSetting | undefined;
|
||||
if (!setting) {
|
||||
throw new Error(`未配置该OAuth类型:${type}`);
|
||||
}
|
||||
@@ -50,19 +68,30 @@ export class ConnectController extends BaseController {
|
||||
if (!addon) {
|
||||
throw new Error("初始化OAuth插件失败");
|
||||
}
|
||||
return addon as IOauthProvider;
|
||||
return {
|
||||
addon: addon as IOauthProvider,
|
||||
setting,
|
||||
};
|
||||
}
|
||||
|
||||
@Post('/login', { description: Constants.per.guest })
|
||||
public async login(@Body(ALL) body: { type: string, forType?:string ,from?:string }) {
|
||||
public async login(@Body(ALL) body: { type: string, subtype?: string, forType?:string ,from?:string }) {
|
||||
|
||||
const addon = await this.getOauthProvider(body.type);
|
||||
const oauthProvider = await this.getOauthProvider(body.type);
|
||||
const installInfo = await this.sysSettingsService.getSetting<SysInstallInfo>(SysInstallInfo);
|
||||
const bindUrl = installInfo?.bindUrl || "";
|
||||
//构造登录url
|
||||
const redirectUrl = `${bindUrl}api/oauth/callback/${body.type}`;
|
||||
const { loginUrl, ticketValue } = await addon.buildLoginUrl({ redirectUri: redirectUrl, forType: body.forType ,from: body.from || "web" });
|
||||
const ticket = this.codeService.setValidationValue(ticketValue)
|
||||
const { loginUrl, ticketValue } = await oauthProvider.addon.buildLoginUrl({
|
||||
redirectUri: redirectUrl,
|
||||
forType: body.forType,
|
||||
from: body.from || "web",
|
||||
subtype: body.subtype,
|
||||
});
|
||||
const ticket = this.codeService.setValidationValue({
|
||||
...ticketValue,
|
||||
subtype: body.subtype,
|
||||
})
|
||||
this.ctx.cookies.set("oauth_ticket", ticket, {
|
||||
httpOnly: true,
|
||||
// secure: true,
|
||||
@@ -78,7 +107,7 @@ export class ConnectController extends BaseController {
|
||||
checkPlus()
|
||||
|
||||
//处理登录回调
|
||||
const addon = await this.getOauthProvider(type);
|
||||
const oauthProvider = await this.getOauthProvider(type);
|
||||
const request = this.ctx.request;
|
||||
// const ticketValue = this.codeService.getValidationValue(ticket);
|
||||
// if (!ticketValue) {
|
||||
@@ -98,7 +127,7 @@ export class ConnectController extends BaseController {
|
||||
const bindUrl = installInfo?.bindUrl || "";
|
||||
const currentUrl = `${bindUrl}api/oauth/callback/${type}?${request.querystring}`
|
||||
try {
|
||||
const tokenRes = await addon.onCallback({
|
||||
const tokenRes = await oauthProvider.addon.onCallback({
|
||||
code: query.code,
|
||||
state: query.state,
|
||||
ticketValue,
|
||||
@@ -108,7 +137,7 @@ export class ConnectController extends BaseController {
|
||||
const userInfo = tokenRes.userInfo;
|
||||
|
||||
const validationCode = await this.codeService.setValidationValue({
|
||||
type,
|
||||
type: getOauthBoundType(type, ticketValue.subtype),
|
||||
userInfo,
|
||||
});
|
||||
|
||||
@@ -129,8 +158,10 @@ export class ConnectController extends BaseController {
|
||||
@Post('/getLogoutUrl', { description: Constants.per.guest })
|
||||
public async logout(@Body(ALL) body: any) {
|
||||
checkPlus()
|
||||
const addon = await this.getOauthProvider(body.type);
|
||||
const { logoutUrl } = await addon.buildLogoutUrl(body);
|
||||
const oauthProvider = await this.getOauthProvider(body.type);
|
||||
const { logoutUrl } = await oauthProvider.addon.buildLogoutUrl({
|
||||
...body,
|
||||
});
|
||||
return this.ok({ logoutUrl });
|
||||
}
|
||||
|
||||
@@ -144,7 +175,7 @@ export class ConnectController extends BaseController {
|
||||
}
|
||||
|
||||
const type = validationValue.type;
|
||||
if (type !== body.type) {
|
||||
if (type !== body.type && !type.startsWith(`${body.type}:`)) {
|
||||
throw new Error("校验码错误");
|
||||
}
|
||||
const userInfo = validationValue.userInfo;
|
||||
@@ -262,16 +293,32 @@ export class ConnectController extends BaseController {
|
||||
provider.addonId = conf.addonId;
|
||||
provider.addonTitle = addonEntity.name;
|
||||
|
||||
const addon = await this.addonGetterService.getAddonById(conf.addonId,true,0,null);
|
||||
const {logoutUrl} = await addon.buildLogoutUrl();
|
||||
const addon = await this.addonGetterService.getAddonById(conf.addonId,true,0,null) as IOauthProvider & { icon?: string; types?: OauthProviderType[] };
|
||||
const {logoutUrl} = await addon.buildLogoutUrl({});
|
||||
if (logoutUrl){
|
||||
provider.logoutUrl = logoutUrl;
|
||||
}
|
||||
if(addon.icon){
|
||||
provider.icon = addon.icon;
|
||||
}
|
||||
if(addon.types?.length){
|
||||
provider.types = addon.types;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (provider.addonId && provider.types?.length) {
|
||||
for (const subtype of provider.types) {
|
||||
list.push({
|
||||
...provider,
|
||||
name: type,
|
||||
subtype: subtype.type,
|
||||
title: subtype.name,
|
||||
icon: subtype.icon || provider.icon,
|
||||
addonTitle: subtype.name,
|
||||
});
|
||||
}
|
||||
continue;
|
||||
}
|
||||
list.push(provider);
|
||||
}
|
||||
|
||||
|
||||
@@ -135,6 +135,7 @@ export class SysSettingsController extends CrudController<SysSettingsService> {
|
||||
await this.service.savePrivateSettings(privateSettings);
|
||||
return this.ok({});
|
||||
}
|
||||
|
||||
@Post('/stopOtherUserTimer', { description: 'sys:settings:edit' })
|
||||
async stopOtherUserTimer(@Body(ALL) body) {
|
||||
await this.pipelineService.stopOtherUserPipeline(1);
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import assert from "assert";
|
||||
import esmock from "esmock";
|
||||
import { AutoFix, buildEabAccountKeyValue, buildLegacyGoogleAccountConfigWhere, parseStorageValue } from "./auto-fix.js";
|
||||
import { AutoFix, buildEabAccountKeyValue, buildLegacyGoogleAccountConfigWhere, buildOauthBoundType, parseStorageValue } from "./auto-fix.js";
|
||||
|
||||
function createAutoFix(options: { pluginConfigService?: any; accessService?: any; storageService?: any }) {
|
||||
function createAutoFix(options: { pluginConfigService?: any; accessService?: any; storageService?: any; sysSettingsService?: any; oauthBoundService?: any }) {
|
||||
const autoFix = new AutoFix();
|
||||
autoFix.pluginConfigService = options.pluginConfigService;
|
||||
autoFix.accessService = options.accessService;
|
||||
autoFix.storageService = options.storageService;
|
||||
autoFix.sysSettingsService = options.sysSettingsService;
|
||||
autoFix.oauthBoundService = options.oauthBoundService;
|
||||
return autoFix;
|
||||
}
|
||||
|
||||
@@ -42,6 +44,11 @@ describe("AutoFix", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("builds OAuth subtype bound type", () => {
|
||||
assert.equal(buildOauthBoundType("clogin", "alipay"), "clogin:alipay");
|
||||
assert.equal(buildOauthBoundType("github"), "github");
|
||||
});
|
||||
|
||||
it("finds legacy Google account config by exact email key only", async () => {
|
||||
let findOneWhere: any;
|
||||
let findCalled = false;
|
||||
@@ -107,6 +114,25 @@ describe("AutoFix", () => {
|
||||
} as any,
|
||||
accessService: null as any,
|
||||
storageService: null as any,
|
||||
sysSettingsService: {
|
||||
async getPublicSettings() {
|
||||
return {
|
||||
oauthProviders: {},
|
||||
};
|
||||
},
|
||||
},
|
||||
oauthBoundService: {
|
||||
async transaction(callback: any) {
|
||||
return await callback({
|
||||
async findOne() {
|
||||
return null;
|
||||
},
|
||||
async update() {
|
||||
return { affected: 0 };
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await autoFix.init();
|
||||
@@ -179,4 +205,97 @@ describe("AutoFix", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("fixes legacy OAuth bound type from string addon loginType and converts loginType to array", async () => {
|
||||
const updates: any[] = [];
|
||||
const autoFix = createAutoFix({
|
||||
pluginConfigService: null as any,
|
||||
accessService: null as any,
|
||||
storageService: null as any,
|
||||
sysSettingsService: {
|
||||
async getPublicSettings() {
|
||||
return {
|
||||
oauthProviders: {
|
||||
clogin: {
|
||||
addonId: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
oauthBoundService: {
|
||||
async transaction(callback: any) {
|
||||
return await callback({
|
||||
async findOne(entity: any, options: any) {
|
||||
assert.equal(entity.name, "AddonEntity");
|
||||
assert.deepEqual(options, { where: { id: 1 } });
|
||||
return {
|
||||
id: 1,
|
||||
setting: JSON.stringify({
|
||||
loginType: "alipay",
|
||||
}),
|
||||
};
|
||||
},
|
||||
async update(entity: any, where: any, value: any) {
|
||||
updates.push({ entity: entity.name, where, value });
|
||||
return { affected: entity.name === "OauthBoundEntity" ? 1 : 0 };
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await autoFix.fixOauthSubtypeBoundType();
|
||||
|
||||
assert.deepEqual(updates[0], {
|
||||
entity: "OauthBoundEntity",
|
||||
where: { type: "clogin" },
|
||||
value: { type: "clogin:alipay" },
|
||||
});
|
||||
assert.equal(updates[1].entity, "AddonEntity");
|
||||
assert.deepEqual(updates[1].where, { id: 1 });
|
||||
assert.deepEqual(JSON.parse(updates[1].value.setting).loginType, ["alipay"]);
|
||||
});
|
||||
|
||||
it("skips OAuth subtype fix when addon loginType is already not legacy string", async () => {
|
||||
let updateCalled = false;
|
||||
const autoFix = createAutoFix({
|
||||
pluginConfigService: null as any,
|
||||
accessService: null as any,
|
||||
storageService: null as any,
|
||||
sysSettingsService: {
|
||||
async getPublicSettings() {
|
||||
return {
|
||||
oauthProviders: {
|
||||
clogin: {
|
||||
addonId: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
oauthBoundService: {
|
||||
async transaction(callback: any) {
|
||||
return await callback({
|
||||
async findOne() {
|
||||
return {
|
||||
id: 1,
|
||||
setting: JSON.stringify({
|
||||
loginType: ["alipay", "github"],
|
||||
}),
|
||||
};
|
||||
},
|
||||
async update() {
|
||||
updateCalled = true;
|
||||
return { affected: 0 };
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await autoFix.fixOauthSubtypeBoundType();
|
||||
|
||||
assert.equal(updateCalled, false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { Inject, Provide, Scope, ScopeEnum } from "@midwayjs/core";
|
||||
import { logger } from "@certd/basic";
|
||||
import { AccessService } from "@certd/lib-server";
|
||||
import { AccessService, AddonEntity, SysSettingsService } from "@certd/lib-server";
|
||||
import { isComm } from "@certd/plus-core";
|
||||
import { PluginConfigService } from "../plugin/service/plugin-config-service.js";
|
||||
import { StorageService } from "../pipeline/service/storage-service.js";
|
||||
import { OauthBoundService } from "../login/service/oauth-bound-service.js";
|
||||
import { OauthBoundEntity } from "../login/entity/oauth-bound.js";
|
||||
|
||||
export function parseStorageValue(value?: string) {
|
||||
if (!value) {
|
||||
@@ -33,6 +35,10 @@ export function buildLegacyGoogleAccountConfigWhere(email: string) {
|
||||
};
|
||||
}
|
||||
|
||||
export function buildOauthBoundType(type: string, subtype?: string) {
|
||||
return subtype ? `${type}:${subtype}` : type;
|
||||
}
|
||||
|
||||
@Provide()
|
||||
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||
export class AutoFix {
|
||||
@@ -45,9 +51,66 @@ export class AutoFix {
|
||||
@Inject()
|
||||
storageService: StorageService;
|
||||
|
||||
@Inject()
|
||||
sysSettingsService: SysSettingsService;
|
||||
|
||||
@Inject()
|
||||
oauthBoundService: OauthBoundService;
|
||||
|
||||
async init() {
|
||||
await this.fixGoogleCommonEabAccountKey();
|
||||
await this.fixOauthSubtypeBoundType();
|
||||
}
|
||||
|
||||
async fixOauthSubtypeBoundType() {
|
||||
try {
|
||||
const publicSettings = await this.sysSettingsService.getPublicSettings();
|
||||
const oauthProviders = publicSettings.oauthProviders || {};
|
||||
await this.oauthBoundService.transaction(async manager => {
|
||||
for (const [type, provider] of Object.entries(oauthProviders)) {
|
||||
if (!provider.addonId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const addonEntity = await manager.findOne(AddonEntity, { where: { id: provider.addonId } });
|
||||
const legacyLoginType = this.getLegacyAddonLoginType(addonEntity?.setting);
|
||||
if (!legacyLoginType) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const newType = buildOauthBoundType(type, legacyLoginType);
|
||||
const res = await manager.update(OauthBoundEntity, { type }, { type: newType });
|
||||
if (res.affected) {
|
||||
logger.info(`已修复OAuth绑定历史数据,${type} -> ${newType},数量=${res.affected}`);
|
||||
}
|
||||
await this.convertLegacyAddonLoginTypeToArray(addonEntity, legacyLoginType, manager);
|
||||
}
|
||||
});
|
||||
} catch (e: any) {
|
||||
logger.error("修复OAuth subtype绑定历史数据失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
private getLegacyAddonLoginType(settingValue?: string) {
|
||||
if (!settingValue) {
|
||||
return null;
|
||||
}
|
||||
const setting = JSON.parse(settingValue);
|
||||
return typeof setting.loginType === "string" && setting.loginType ? setting.loginType : null;
|
||||
}
|
||||
|
||||
private async convertLegacyAddonLoginTypeToArray(addonEntity: AddonEntity | null, loginType: string, manager: any) {
|
||||
if (!addonEntity?.setting) {
|
||||
return;
|
||||
}
|
||||
const setting = JSON.parse(addonEntity.setting);
|
||||
if (typeof setting.loginType !== "string") {
|
||||
return;
|
||||
}
|
||||
setting.loginType = [loginType];
|
||||
await manager.update(AddonEntity, { id: addonEntity.id }, { setting: JSON.stringify(setting) });
|
||||
}
|
||||
|
||||
async fixGoogleCommonEabAccountKey() {
|
||||
if (!isComm()) {
|
||||
return;
|
||||
@@ -100,7 +163,7 @@ export class AutoFix {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
parseStorageValue(value?: string) {
|
||||
return parseStorageValue(value);
|
||||
}
|
||||
|
||||
@@ -245,7 +245,8 @@ export class LoginService {
|
||||
async loginByOpenId(req: { openId: string, type:string }) {
|
||||
const {openId, type} = req;
|
||||
const oauthBound = await this.oauthBoundService.findOne({
|
||||
where:{openId, type}
|
||||
where:{openId, type: type.replace(':', '')')}
|
||||
});
|
||||
});
|
||||
if (oauthBound == null) {
|
||||
return null
|
||||
|
||||
@@ -41,9 +41,11 @@ export type BuildLoginUrlReq = {
|
||||
redirectUri: string;
|
||||
forType?: string;
|
||||
from?:string;
|
||||
subtype?: string;
|
||||
}
|
||||
|
||||
export type BuildLogoutUrlReq = {
|
||||
subtype?: string;
|
||||
}
|
||||
|
||||
export type LogoutUrlReply = {
|
||||
@@ -54,4 +56,4 @@ export interface IOauthProvider {
|
||||
buildLoginUrl: (params: BuildLoginUrlReq) => Promise<LoginUrlReply>;
|
||||
onCallback: (params: OnCallbackReq) => Promise<OauthToken>;
|
||||
buildLogoutUrl: (params: BuildLogoutUrlReq) => Promise<LogoutUrlReply>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,31 @@
|
||||
import { AddonInput, BaseAddon, IsAddon } from "@certd/lib-server";
|
||||
import { BuildLoginUrlReq, BuildLogoutUrlReq, IOauthProvider, OnCallbackReq } from "../api.js";
|
||||
import { IconSets } from "../iconsets.js";
|
||||
|
||||
const CLOGIN_TYPES = [
|
||||
{ label: "QQ", value: "qq", icon: "logos:tencent-qq" },
|
||||
{ label: "微信", value: "wx", icon: "logos:wechat-icon" },
|
||||
{ label: "支付宝", value: "alipay", icon: "simple-icons:alipay:#0099ff" },
|
||||
{ label: "微博", value: "sina", icon: "logos:sina-weibo" },
|
||||
{ label: "百度", value: "baidu", icon: "logos:baidu" },
|
||||
{ label: "华为", value: "huawei", icon: "simple-icons:huawei:#ff0000" },
|
||||
{ label: "小米", value: "xiaomi", icon: "logos:xiaomi-icon" },
|
||||
{ label: "谷歌", value: "google", icon: "logos:google-icon" },
|
||||
{ label: "微软", value: "microsoft", icon: "logos:microsoft-icon" },
|
||||
{ label: "Facebook", value: "facebook", icon: "logos:facebook" },
|
||||
{ label: "Twitter", value: "twitter", icon: "logos:twitter" },
|
||||
{ label: "钉钉", value: "dingtalk", icon: "logos:dingtalk" },
|
||||
{ label: "Gitee", value: "gitee", icon: "simple-icons:gitee:#c71d23" },
|
||||
{ label: "Github", value: "github", icon: "logos:github-icon" },
|
||||
];
|
||||
|
||||
function getCloginType(subtype?: string, loginType?: string | string[]) {
|
||||
const types = Array.isArray(loginType) ? loginType : [loginType];
|
||||
const type = subtype || types.find(item => !!item);
|
||||
if (!type) {
|
||||
throw new Error("请选择彩虹聚合登录类型");
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
@IsAddon({
|
||||
addonType: "oauth",
|
||||
@@ -22,38 +47,27 @@ export class CloginOauthProvider extends BaseAddon implements IOauthProvider {
|
||||
@AddonInput({
|
||||
title: "登录类型",
|
||||
component: {
|
||||
name: "a-auto-complete",
|
||||
options: [
|
||||
{ label: "QQ", value: "qq" },
|
||||
{ label: "微信", value: "wx" },
|
||||
{ label: "支付宝", value: "alipay" },
|
||||
{ label: "微博", value: "sina" },
|
||||
{ label: "百度", value: "baidu" },
|
||||
{ label: "华为", value: "huawei" },
|
||||
{ label: "小米", value: "xiaomi" },
|
||||
{ label: "谷歌", value: "google" },
|
||||
{ label: "微软", value: "microsoft" },
|
||||
{ label: "Facebook", value: "facebook" },
|
||||
{ label: "Twitter", value: "twitter" },
|
||||
{ label: "钉钉", value: "dingtalk" },
|
||||
{ label: "Gitee", value: "gitee" },
|
||||
{ label: "Github", value: "github" },
|
||||
]
|
||||
name: "a-select",
|
||||
vModel: "value",
|
||||
mode: "tags",
|
||||
multiple: true,
|
||||
options: CLOGIN_TYPES,
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
loginType = "";
|
||||
loginType: string[] | string = [];
|
||||
|
||||
@AddonInput({
|
||||
title: "自定义图标",
|
||||
component: {
|
||||
name:"fs-icon-selector",
|
||||
vModel:"modelValue",
|
||||
iconSets: IconSets,
|
||||
},
|
||||
required: false,
|
||||
})
|
||||
icon = "";
|
||||
get types() {
|
||||
const loginTypes = Array.isArray(this.loginType) ? this.loginType : [this.loginType].filter(Boolean);
|
||||
return loginTypes.map(type => {
|
||||
const option = CLOGIN_TYPES.find(item => item.value === type);
|
||||
return {
|
||||
type,
|
||||
name: option?.label || type,
|
||||
icon: option?.icon,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@AddonInput({
|
||||
title: "AppId",
|
||||
@@ -75,11 +89,12 @@ export class CloginOauthProvider extends BaseAddon implements IOauthProvider {
|
||||
async buildLoginUrl(params: BuildLoginUrlReq) {
|
||||
|
||||
let redirectUri = params.redirectUri || ""
|
||||
const loginType = getCloginType(params.subtype, this.loginType);
|
||||
// if(redirectUri.indexOf("localhost:3008")>=0){
|
||||
// redirectUri = redirectUri.replace("localhost:3008", "certd.handfree.work")
|
||||
// }
|
||||
const res = await this.ctx.http.request({
|
||||
url: `${this.endpoint}/connect.php?act=login&appid=${this.appId}&appkey=${this.appKey}&type=${this.loginType}&redirect_uri=${redirectUri}`
|
||||
url: `${this.endpoint}/connect.php?act=login&appid=${this.appId}&appkey=${this.appKey}&type=${loginType}&redirect_uri=${redirectUri}`
|
||||
})
|
||||
|
||||
this.checkRes(res)
|
||||
@@ -103,8 +118,9 @@ export class CloginOauthProvider extends BaseAddon implements IOauthProvider {
|
||||
//校验state
|
||||
|
||||
const code = req.code || ""
|
||||
const loginType = getCloginType(req.ticketValue?.subtype, this.loginType);
|
||||
|
||||
const tokenEndpoint = `${this.endpoint}/connect.php?act=callback&appid=${this.appId}&appkey=${this.appKey}&type=${this.loginType}&code=${code}`
|
||||
const tokenEndpoint = `${this.endpoint}/connect.php?act=callback&appid=${this.appId}&appkey=${this.appKey}&type=${loginType}&code=${code}`
|
||||
const res = await this.ctx.utils.http.request({
|
||||
url: tokenEndpoint,
|
||||
method: "post",
|
||||
|
||||
Generated
+47
-108
@@ -52,7 +52,7 @@ importers:
|
||||
packages/core/acme-client:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../basic
|
||||
'@peculiar/x509':
|
||||
specifier: ^1.11.0
|
||||
@@ -234,11 +234,11 @@ importers:
|
||||
packages/core/pipeline:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../basic
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.39.14
|
||||
version: 1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../pro/plus-core
|
||||
dayjs:
|
||||
specifier: ^1.11.7
|
||||
version: 1.11.13
|
||||
@@ -457,7 +457,7 @@ importers:
|
||||
packages/libs/lib-k8s:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../core/basic
|
||||
'@kubernetes/client-node':
|
||||
specifier: 0.21.0
|
||||
@@ -503,20 +503,20 @@ importers:
|
||||
packages/libs/lib-server:
|
||||
dependencies:
|
||||
'@certd/acme-client':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../core/acme-client
|
||||
'@certd/basic':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../core/basic
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plugin-lib':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../plugins/plugin-lib
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.39.14
|
||||
version: 1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../pro/plus-core
|
||||
'@midwayjs/cache':
|
||||
specifier: 3.14.0
|
||||
version: 3.14.0
|
||||
@@ -679,16 +679,16 @@ importers:
|
||||
packages/plugins/plugin-cert:
|
||||
dependencies:
|
||||
'@certd/acme-client':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../core/acme-client
|
||||
'@certd/basic':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../core/basic
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plugin-lib':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../plugin-lib
|
||||
psl:
|
||||
specifier: ^1.9.0
|
||||
@@ -758,17 +758,17 @@ importers:
|
||||
specifier: ^3.964.0
|
||||
version: 3.964.0(aws-crt@1.26.2)
|
||||
'@certd/acme-client':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../core/acme-client
|
||||
'@certd/basic':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../core/basic
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.39.14
|
||||
version: 1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../pro/plus-core
|
||||
'@kubernetes/client-node':
|
||||
specifier: 0.21.0
|
||||
version: 0.21.0
|
||||
@@ -867,16 +867,16 @@ importers:
|
||||
packages/pro/commercial-core:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../core/basic
|
||||
'@certd/lib-server':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../libs/lib-server
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../plus-core
|
||||
'@midwayjs/core':
|
||||
specifier: 3.20.11
|
||||
@@ -967,16 +967,16 @@ importers:
|
||||
packages/pro/plugin-plus:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../core/basic
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plugin-lib':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../plugins/plugin-lib
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../plus-core
|
||||
crypto-js:
|
||||
specifier: ^4.2.0
|
||||
@@ -1061,7 +1061,7 @@ importers:
|
||||
packages/pro/plus-core:
|
||||
dependencies:
|
||||
'@certd/basic':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../core/basic
|
||||
dayjs:
|
||||
specifier: ^1.11.7
|
||||
@@ -1363,10 +1363,10 @@ importers:
|
||||
version: 0.1.3(zod@3.24.4)
|
||||
devDependencies:
|
||||
'@certd/lib-iframe':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../libs/lib-iframe
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../core/pipeline
|
||||
'@rollup/plugin-commonjs':
|
||||
specifier: ^25.0.7
|
||||
@@ -1573,47 +1573,47 @@ importers:
|
||||
specifier: ^4.13.1
|
||||
version: 4.13.1
|
||||
'@certd/acme-client':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../core/acme-client
|
||||
'@certd/basic':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../core/basic
|
||||
'@certd/commercial-core':
|
||||
specifier: ^1.39.14
|
||||
version: 1.39.14(better-sqlite3@11.10.0)(mysql2@3.14.1)(pg@8.16.0)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@18.19.100)(typescript@5.9.3))
|
||||
specifier: ^1.39.16
|
||||
version: link:../../pro/commercial-core
|
||||
'@certd/cv4pve-api-javascript':
|
||||
specifier: ^8.4.2
|
||||
version: 8.4.2
|
||||
'@certd/jdcloud':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../libs/lib-jdcloud
|
||||
'@certd/lib-huawei':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../libs/lib-huawei
|
||||
'@certd/lib-k8s':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../libs/lib-k8s
|
||||
'@certd/lib-server':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../libs/lib-server
|
||||
'@certd/midway-flyway-js':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../libs/midway-flyway-js
|
||||
'@certd/pipeline':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../core/pipeline
|
||||
'@certd/plugin-cert':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../plugins/plugin-cert
|
||||
'@certd/plugin-lib':
|
||||
specifier: ^1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../plugins/plugin-lib
|
||||
'@certd/plugin-plus':
|
||||
specifier: ^1.39.14
|
||||
version: 1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../pro/plugin-plus
|
||||
'@certd/plus-core':
|
||||
specifier: ^1.39.14
|
||||
version: 1.39.14
|
||||
specifier: ^1.39.16
|
||||
version: link:../../pro/plus-core
|
||||
'@google-cloud/dns':
|
||||
specifier: ^5.3.1
|
||||
version: 5.3.1
|
||||
@@ -3033,18 +3033,9 @@ packages:
|
||||
'@better-scroll/zoom@2.5.1':
|
||||
resolution: {integrity: sha512-aGvFY5ooeZWS4RcxQLD+pGLpQHQxpPy0sMZV3yadcd2QK53PK9gS4Dp+BYfRv8lZ4/P2LoNEhr6Wq1DN6+uPlA==}
|
||||
|
||||
'@certd/commercial-core@1.39.14':
|
||||
resolution: {integrity: sha512-Tys+rjy1zuATSwjqpFKpKCYpz6RoC3gIGYcVjD+qKvTabTSeChvwRjvDvzSiyWpU5iHm6uT+7tpPTc0/XXFvBg==}
|
||||
|
||||
'@certd/cv4pve-api-javascript@8.4.2':
|
||||
resolution: {integrity: sha512-udGce7ewrVl4DmZvX+17PjsnqsdDIHEDatr8QP0AVrY2p+8JkaSPW4mXCKiLGf82C9K2+GXgT+qNIqgW7tfF9Q==}
|
||||
|
||||
'@certd/plugin-plus@1.39.14':
|
||||
resolution: {integrity: sha512-79PX/YmaCqst5StYAB9WfbOhrEAeGbO9ypeSJTTsZhNkqbYEAlqnk/6upEpgdxnHxQ+WNH8DlInMCdJhX26HDw==}
|
||||
|
||||
'@certd/plus-core@1.39.14':
|
||||
resolution: {integrity: sha512-GRJi9mBjrtfng1NbEeKe75AJ6sbfNCUKo1I6G2oYC8DdlGlJ/7XblZ44lwEWMa1IHB2ere51i9TqmZtosmt1FA==}
|
||||
|
||||
'@certd/vue-js-cron-core@6.0.3':
|
||||
resolution: {integrity: sha512-kqzoAMhYz9j6FGNWEODRYtt4NpUEUwjpkU89z5WVg2tCtOcI5VhwyUGOd8AxiBCRfd6PtXvzuqw85PaOps9wrQ==}
|
||||
|
||||
@@ -15573,64 +15564,12 @@ snapshots:
|
||||
dependencies:
|
||||
'@better-scroll/core': 2.5.1
|
||||
|
||||
'@certd/commercial-core@1.39.14(better-sqlite3@11.10.0)(mysql2@3.14.1)(pg@8.16.0)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@18.19.100)(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@certd/basic': link:packages/core/basic
|
||||
'@certd/lib-server': link:packages/libs/lib-server
|
||||
'@certd/pipeline': link:packages/core/pipeline
|
||||
'@certd/plus-core': 1.39.14
|
||||
'@midwayjs/core': 3.20.11
|
||||
'@midwayjs/koa': 3.20.13
|
||||
'@midwayjs/logger': 3.4.2
|
||||
'@midwayjs/swagger': 3.20.11
|
||||
'@midwayjs/typeorm': 3.20.11
|
||||
dayjs: 1.11.13
|
||||
typeorm: 0.3.24(better-sqlite3@11.10.0)(mysql2@3.14.1)(pg@8.16.0)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@18.19.100)(typescript@5.9.3))
|
||||
transitivePeerDependencies:
|
||||
- '@google-cloud/spanner'
|
||||
- '@sap/hana-client'
|
||||
- babel-plugin-macros
|
||||
- better-sqlite3
|
||||
- hdb-pool
|
||||
- ioredis
|
||||
- mongodb
|
||||
- mssql
|
||||
- mysql2
|
||||
- oracledb
|
||||
- pg
|
||||
- pg-native
|
||||
- pg-query-stream
|
||||
- redis
|
||||
- reflect-metadata
|
||||
- sql.js
|
||||
- sqlite3
|
||||
- supports-color
|
||||
- ts-node
|
||||
- typeorm-aurora-data-api-driver
|
||||
|
||||
'@certd/cv4pve-api-javascript@8.4.2':
|
||||
dependencies:
|
||||
debug: 4.4.3(supports-color@8.1.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@certd/plugin-plus@1.39.14':
|
||||
dependencies:
|
||||
'@certd/basic': link:packages/core/basic
|
||||
'@certd/pipeline': link:packages/core/pipeline
|
||||
'@certd/plugin-lib': link:packages/plugins/plugin-lib
|
||||
'@certd/plus-core': 1.39.14
|
||||
crypto-js: 4.2.0
|
||||
dayjs: 1.11.13
|
||||
form-data: 4.0.2
|
||||
jsrsasign: 11.1.0
|
||||
querystring: 0.2.1
|
||||
|
||||
'@certd/plus-core@1.39.14':
|
||||
dependencies:
|
||||
'@certd/basic': link:packages/core/basic
|
||||
dayjs: 1.11.13
|
||||
|
||||
'@certd/vue-js-cron-core@6.0.3':
|
||||
dependencies:
|
||||
mustache: 4.2.0
|
||||
|
||||
@@ -1 +1 @@
|
||||
00:51
|
||||
17:29
|
||||
|
||||
Reference in New Issue
Block a user