mirror of
https://github.com/certd/certd.git
synced 2026-04-24 12:27:25 +08:00
Merge branch 'v2-dev' into v2_admin_mode
This commit is contained in:
@@ -3,6 +3,16 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.38.6](https://github.com/certd/certd/compare/v1.38.5...v1.38.6) (2026-02-04)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复新网找错域名的bug ([bd511f9](https://github.com/certd/certd/commit/bd511f97cb7fbdcaeff7ac899f0460a5c7b41826))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* oauth支持github 和google, 修复头像显示问题 ([693a4a6](https://github.com/certd/certd/commit/693a4a663385ced3176286bf4b5f3566da83d90e))
|
||||
|
||||
## [1.38.5](https://github.com/certd/certd/compare/v1.38.4...v1.38.5) (2026-02-02)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -22,7 +22,9 @@ input:
|
||||
component:
|
||||
name: api-test
|
||||
action: TestRequest
|
||||
helper: 点击测试接口是否正常
|
||||
helper: |-
|
||||
测试前请务必先在新网后台关闭异地登录保护、关闭动态口令验证
|
||||
如果提示需要短信验证码,请等几个小时后再试
|
||||
pluginType: access
|
||||
type: builtIn
|
||||
scriptFilePath: /plugins/plugin-xinnet/access.js
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
addonType: oauth
|
||||
name: github
|
||||
title: GitHub认证
|
||||
desc: GitHub OAuth2登录
|
||||
icon: simple-icons:github
|
||||
showTest: false
|
||||
input:
|
||||
clientId:
|
||||
title: ClientId
|
||||
helper: '[GitHub Developer Settings](https://github.com/settings/developers)创建应用后获取'
|
||||
required: true
|
||||
clientSecretKey:
|
||||
title: ClientSecretKey
|
||||
component:
|
||||
placeholder: ClientSecretKey / appSecretKey
|
||||
required: true
|
||||
pluginType: addon
|
||||
type: builtIn
|
||||
scriptFilePath: /plugins/plugin-oauth/oauth2/plugin-github.js
|
||||
@@ -0,0 +1,21 @@
|
||||
addonType: oauth
|
||||
name: google
|
||||
title: Google认证
|
||||
desc: Google OAuth2登录
|
||||
icon: simple-icons:google
|
||||
showTest: false
|
||||
input:
|
||||
clientId:
|
||||
title: ClientId
|
||||
helper: >-
|
||||
[Google Cloud
|
||||
Console](https://console.cloud.google.com/apis/credentials)创建应用后获取
|
||||
required: true
|
||||
clientSecretKey:
|
||||
title: ClientSecretKey
|
||||
component:
|
||||
placeholder: ClientSecretKey / appSecretKey
|
||||
required: true
|
||||
pluginType: addon
|
||||
type: builtIn
|
||||
scriptFilePath: /plugins/plugin-oauth/oauth2/plugin-google.js
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/ui-server",
|
||||
"version": "1.38.5",
|
||||
"version": "1.38.6",
|
||||
"description": "fast-server base midway",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
@@ -48,20 +48,20 @@
|
||||
"@aws-sdk/client-iam": "^3.964.0",
|
||||
"@aws-sdk/client-route-53": "^3.964.0",
|
||||
"@aws-sdk/client-s3": "^3.964.0",
|
||||
"@certd/acme-client": "^1.38.5",
|
||||
"@certd/basic": "^1.38.5",
|
||||
"@certd/commercial-core": "^1.38.5",
|
||||
"@certd/acme-client": "^1.38.6",
|
||||
"@certd/basic": "^1.38.6",
|
||||
"@certd/commercial-core": "^1.38.6",
|
||||
"@certd/cv4pve-api-javascript": "^8.4.2",
|
||||
"@certd/jdcloud": "^1.38.5",
|
||||
"@certd/lib-huawei": "^1.38.5",
|
||||
"@certd/lib-k8s": "^1.38.5",
|
||||
"@certd/lib-server": "^1.38.5",
|
||||
"@certd/midway-flyway-js": "^1.38.5",
|
||||
"@certd/pipeline": "^1.38.5",
|
||||
"@certd/plugin-cert": "^1.38.5",
|
||||
"@certd/plugin-lib": "^1.38.5",
|
||||
"@certd/plugin-plus": "^1.38.5",
|
||||
"@certd/plus-core": "^1.38.5",
|
||||
"@certd/jdcloud": "^1.38.6",
|
||||
"@certd/lib-huawei": "^1.38.6",
|
||||
"@certd/lib-k8s": "^1.38.6",
|
||||
"@certd/lib-server": "^1.38.6",
|
||||
"@certd/midway-flyway-js": "^1.38.6",
|
||||
"@certd/pipeline": "^1.38.6",
|
||||
"@certd/plugin-cert": "^1.38.6",
|
||||
"@certd/plugin-lib": "^1.38.6",
|
||||
"@certd/plugin-plus": "^1.38.6",
|
||||
"@certd/plus-core": "^1.38.6",
|
||||
"@google-cloud/publicca": "^1.3.0",
|
||||
"@huaweicloud/huaweicloud-sdk-cdn": "^3.1.185",
|
||||
"@huaweicloud/huaweicloud-sdk-core": "^3.1.185",
|
||||
|
||||
@@ -84,5 +84,9 @@ export function startProxyServer(opts:{port:number}) {
|
||||
logger.info(`[proxy] 正向代理服务器运行在 http://0.0.0.0:${port}`);
|
||||
});
|
||||
|
||||
proxyServer.close(() => {
|
||||
logger.info('[proxy] 正向代理服务器已关闭');
|
||||
});
|
||||
|
||||
return proxyServer
|
||||
}
|
||||
@@ -113,6 +113,9 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||
|
||||
async add(bean: PipelineEntity) {
|
||||
bean.status = ResultType.none;
|
||||
if (bean.order == null) {
|
||||
bean.order = 0;
|
||||
}
|
||||
await this.save(bean);
|
||||
return bean;
|
||||
}
|
||||
@@ -243,6 +246,9 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||
if (!bean.status) {
|
||||
bean.status = ResultType.none;
|
||||
}
|
||||
if (bean.order == null) {
|
||||
bean.order = 0;
|
||||
}
|
||||
if (!isUpdate) {
|
||||
//如果是添加,先保存一下,获取到id,更新pipeline.id
|
||||
await this.addOrUpdate(bean);
|
||||
|
||||
@@ -147,7 +147,7 @@ export class AcmeService {
|
||||
externalAccountBinding: this.eab,
|
||||
backoffAttempts: this.options.maxCheckRetryCount || 20,
|
||||
backoffMin: 5000,
|
||||
backoffMax: 10000,
|
||||
backoffMax: 1000*1000,
|
||||
urlMapping,
|
||||
signal: this.options.signal,
|
||||
logger: this.logger,
|
||||
|
||||
@@ -264,7 +264,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
name: "access-selector",
|
||||
type: "eab",
|
||||
},
|
||||
maybeNeed: true,
|
||||
maybeNeed: false,
|
||||
required: false,
|
||||
helper:
|
||||
"需要提供EAB授权" +
|
||||
@@ -291,7 +291,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
name: "access-selector",
|
||||
type: "google",
|
||||
},
|
||||
maybeNeed: true,
|
||||
maybeNeed: false,
|
||||
required: false,
|
||||
helper: "google服务账号授权与EAB授权选填其中一个,[服务账号授权获取方法](https://certd.docmirror.cn/guide/use/google/)\n服务账号授权需要配置代理或者服务器本身在海外",
|
||||
mergeScript: `
|
||||
|
||||
@@ -2,4 +2,7 @@ export * from './api.js'
|
||||
export * from './oidc/plugin-oidc.js'
|
||||
export * from './wx/plugin-wx.js'
|
||||
export * from './oauth2/plugin-gitee.js'
|
||||
export * from './oauth2/plugin-clogin.js'
|
||||
export * from './oauth2/plugin-clogin.js'
|
||||
export * from './oauth2/plugin-github.js'
|
||||
export * from './oauth2/plugin-google.js'
|
||||
export * from './oauth2/plugin-microsoft.js'
|
||||
@@ -0,0 +1,103 @@
|
||||
import { AddonInput, BaseAddon, IsAddon } from "@certd/lib-server";
|
||||
import { BuildLoginUrlReq, BuildLogoutUrlReq, IOauthProvider, OnCallbackReq } from "../api.js";
|
||||
|
||||
@IsAddon({
|
||||
addonType: "oauth",
|
||||
name: 'github',
|
||||
title: 'GitHub认证',
|
||||
desc: 'GitHub OAuth2登录',
|
||||
icon:"simple-icons:github",
|
||||
showTest: false,
|
||||
})
|
||||
export class GithubOauthProvider extends BaseAddon implements IOauthProvider {
|
||||
|
||||
@AddonInput({
|
||||
title: "ClientId",
|
||||
helper: "[GitHub Developer Settings](https://github.com/settings/developers)创建应用后获取",
|
||||
required: true,
|
||||
})
|
||||
clientId = "";
|
||||
|
||||
@AddonInput({
|
||||
title: "ClientSecretKey",
|
||||
component: {
|
||||
placeholder: "ClientSecretKey / appSecretKey",
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
clientSecretKey = "";
|
||||
|
||||
async buildLoginUrl(params: BuildLoginUrlReq) {
|
||||
|
||||
let scope = "user:email" // Scope of the access request
|
||||
let state:any = {
|
||||
forType: params.forType || 'login',
|
||||
}
|
||||
state = this.ctx.utils.hash.base64(JSON.stringify(state))
|
||||
|
||||
const authorizeEndpoint = "https://github.com/login/oauth/authorize"
|
||||
const redirectUrl = encodeURIComponent(params.redirectUri)
|
||||
const loginUrl = `${authorizeEndpoint}?client_id=${this.clientId}&redirect_uri=${redirectUrl}&response_type=code&scope=${scope}&state=${state}`
|
||||
return {
|
||||
loginUrl,
|
||||
ticketValue: {
|
||||
state,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async onCallback(req: OnCallbackReq) {
|
||||
|
||||
const code = req.code || ""
|
||||
|
||||
const tokenEndpoint = "https://github.com/login/oauth/access_token"
|
||||
|
||||
const uri = new URL(req.currentURL)
|
||||
const redirectUri = `${uri.origin}${uri.pathname}`
|
||||
const res = await this.ctx.utils.http.request( {
|
||||
url: tokenEndpoint,
|
||||
method: "post",
|
||||
headers: {
|
||||
"Accept": "application/json"
|
||||
},
|
||||
data:{
|
||||
client_id: this.clientId,
|
||||
client_secret: this.clientSecretKey,
|
||||
code,
|
||||
redirect_uri: redirectUri
|
||||
}
|
||||
})
|
||||
|
||||
const tokens = res
|
||||
|
||||
const userInfoEndpoint = "https://api.github.com/user"
|
||||
|
||||
// 获取用户信息
|
||||
const userInfoRes = await this.ctx.utils.http.request( {
|
||||
url: userInfoEndpoint,
|
||||
method: "get",
|
||||
headers: {
|
||||
"Authorization": `Bearer ${tokens.access_token}`,
|
||||
"Accept": "application/json"
|
||||
}
|
||||
})
|
||||
const userInfo = userInfoRes
|
||||
|
||||
return {
|
||||
token:{
|
||||
accessToken: tokens.access_token,
|
||||
refreshToken: tokens.refresh_token,
|
||||
expiresIn: tokens.expires_in,
|
||||
},
|
||||
userInfo: {
|
||||
openId: userInfo.id,
|
||||
nickName: userInfo.login || userInfo.name || "",
|
||||
avatar: userInfo.avatar_url,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
async buildLogoutUrl(params: BuildLogoutUrlReq) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
import { AddonInput, BaseAddon, IsAddon } from "@certd/lib-server";
|
||||
import { BuildLoginUrlReq, BuildLogoutUrlReq, IOauthProvider, OnCallbackReq } from "../api.js";
|
||||
|
||||
@IsAddon({
|
||||
addonType: "oauth",
|
||||
name: 'google',
|
||||
title: 'Google认证',
|
||||
desc: 'Google OAuth2登录',
|
||||
icon:"simple-icons:google",
|
||||
showTest: false,
|
||||
})
|
||||
export class GoogleOauthProvider extends BaseAddon implements IOauthProvider {
|
||||
|
||||
@AddonInput({
|
||||
title: "ClientId",
|
||||
helper: "[Google Cloud Console](https://console.cloud.google.com/apis/credentials)创建应用后获取",
|
||||
required: true,
|
||||
})
|
||||
clientId = "";
|
||||
|
||||
@AddonInput({
|
||||
title: "ClientSecretKey",
|
||||
component: {
|
||||
placeholder: "ClientSecretKey / appSecretKey",
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
clientSecretKey = "";
|
||||
|
||||
async buildLoginUrl(params: BuildLoginUrlReq) {
|
||||
|
||||
let scope = "email profile" // Scope of the access request
|
||||
let state:any = {
|
||||
forType: params.forType || 'login',
|
||||
}
|
||||
state = this.ctx.utils.hash.base64(JSON.stringify(state))
|
||||
|
||||
const authorizeEndpoint = "https://accounts.google.com/o/oauth2/auth"
|
||||
const redirectUrl = encodeURIComponent(params.redirectUri)
|
||||
const loginUrl = `${authorizeEndpoint}?client_id=${this.clientId}&redirect_uri=${redirectUrl}&response_type=code&scope=${scope}&state=${state}`
|
||||
return {
|
||||
loginUrl,
|
||||
ticketValue: {
|
||||
state,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async onCallback(req: OnCallbackReq) {
|
||||
|
||||
const code = req.code || ""
|
||||
|
||||
const tokenEndpoint = "https://oauth2.googleapis.com/token"
|
||||
|
||||
const uri = new URL(req.currentURL)
|
||||
const redirectUri = `${uri.origin}${uri.pathname}`
|
||||
const res = await this.ctx.utils.http.request( {
|
||||
url: tokenEndpoint,
|
||||
method: "post",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded"
|
||||
},
|
||||
data:{
|
||||
client_id: this.clientId,
|
||||
client_secret: this.clientSecretKey,
|
||||
code,
|
||||
redirect_uri: redirectUri,
|
||||
grant_type: "authorization_code"
|
||||
}
|
||||
})
|
||||
|
||||
const tokens = res
|
||||
|
||||
const userInfoEndpoint = "https://www.googleapis.com/oauth2/v3/userinfo"
|
||||
|
||||
// 获取用户信息
|
||||
const userInfoRes = await this.ctx.utils.http.request( {
|
||||
url: userInfoEndpoint,
|
||||
method: "get",
|
||||
headers: {
|
||||
"Authorization": `Bearer ${tokens.access_token}`
|
||||
}
|
||||
})
|
||||
const userInfo = userInfoRes
|
||||
|
||||
return {
|
||||
token:{
|
||||
accessToken: tokens.access_token,
|
||||
refreshToken: tokens.refresh_token,
|
||||
expiresIn: tokens.expires_in,
|
||||
},
|
||||
userInfo: {
|
||||
openId: userInfo.sub,
|
||||
nickName: userInfo.name || userInfo.email || "",
|
||||
avatar: userInfo.picture,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
async buildLogoutUrl(params: BuildLogoutUrlReq) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
import { AddonInput, BaseAddon, IsAddon } from "@certd/lib-server";
|
||||
import { BuildLoginUrlReq, BuildLogoutUrlReq, IOauthProvider, OnCallbackReq } from "../api.js";
|
||||
|
||||
@IsAddon({
|
||||
addonType: "oauth",
|
||||
name: 'microsoft',
|
||||
title: 'Microsoft认证',
|
||||
desc: 'Microsoft OAuth2登录',
|
||||
icon:"simple-icons:microsoft",
|
||||
showTest: false,
|
||||
})
|
||||
export class MicrosoftOauthProvider extends BaseAddon implements IOauthProvider {
|
||||
|
||||
@AddonInput({
|
||||
title: "ClientId",
|
||||
helper: "[Azure Portal](https://portal.azure.com/)创建应用后获取",
|
||||
required: true,
|
||||
})
|
||||
clientId = "";
|
||||
|
||||
@AddonInput({
|
||||
title: "ClientSecretKey",
|
||||
component: {
|
||||
placeholder: "ClientSecretKey / appSecretKey",
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
clientSecretKey = "";
|
||||
|
||||
@AddonInput({
|
||||
title: "TenantId",
|
||||
helper: "租户ID,留空使用/common端点(需要应用配置为多租户)",
|
||||
component: {
|
||||
placeholder: "common 或 租户ID",
|
||||
},
|
||||
value: "common",
|
||||
required: false,
|
||||
})
|
||||
tenantId = "common";
|
||||
|
||||
async buildLoginUrl(params: BuildLoginUrlReq) {
|
||||
|
||||
let scope = "openid profile email User.Read" // Scope of the access request
|
||||
let state:any = {
|
||||
forType: params.forType || 'login',
|
||||
}
|
||||
state = this.ctx.utils.hash.base64(JSON.stringify(state))
|
||||
|
||||
const authorizeEndpoint = `https://login.microsoftonline.com/${this.tenantId}/oauth2/v2.0/authorize`
|
||||
const redirectUrl = encodeURIComponent(params.redirectUri)
|
||||
const loginUrl = `${authorizeEndpoint}?client_id=${this.clientId}&redirect_uri=${redirectUrl}&response_type=code&scope=${scope}&state=${state}`
|
||||
return {
|
||||
loginUrl,
|
||||
ticketValue: {
|
||||
state,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async onCallback(req: OnCallbackReq) {
|
||||
|
||||
const code = req.code || ""
|
||||
if (!code) {
|
||||
throw new Error("Missing code parameter");
|
||||
}
|
||||
|
||||
const tokenEndpoint = `https://login.microsoftonline.com/${this.tenantId}/oauth2/v2.0/token`
|
||||
|
||||
const uri = new URL(req.currentURL)
|
||||
const redirectUri = `${uri.origin}${uri.pathname}`
|
||||
|
||||
// 构建 form-urlencoded 格式的数据
|
||||
const formData = new URLSearchParams();
|
||||
formData.append('client_id', this.clientId);
|
||||
formData.append('client_secret', this.clientSecretKey);
|
||||
formData.append('code', code);
|
||||
formData.append('redirect_uri', redirectUri);
|
||||
formData.append('grant_type', 'authorization_code');
|
||||
|
||||
const res = await this.ctx.utils.http.request( {
|
||||
url: tokenEndpoint,
|
||||
method: "post",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"Accept": "application/json"
|
||||
},
|
||||
data: formData.toString()
|
||||
})
|
||||
|
||||
const tokens = res
|
||||
|
||||
const userInfoEndpoint = "https://graph.microsoft.com/v1.0/me"
|
||||
|
||||
// 获取用户信息
|
||||
const userInfoRes = await this.ctx.utils.http.request( {
|
||||
url: userInfoEndpoint,
|
||||
method: "get",
|
||||
headers: {
|
||||
"Authorization": `Bearer ${tokens.access_token}`,
|
||||
"Accept": "application/json"
|
||||
}
|
||||
})
|
||||
const userInfo = userInfoRes
|
||||
|
||||
return {
|
||||
token:{
|
||||
accessToken: tokens.access_token,
|
||||
refreshToken: tokens.refresh_token,
|
||||
expiresIn: tokens.expires_in,
|
||||
},
|
||||
userInfo: {
|
||||
openId: userInfo.id,
|
||||
nickName: userInfo.displayName || userInfo.userPrincipalName || "",
|
||||
avatar: userInfo.avatar || "",
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
async buildLogoutUrl(params: BuildLogoutUrlReq) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user