diff --git a/packages/ui/certd-client/src/api/service.ts b/packages/ui/certd-client/src/api/service.ts index 12418ab3c..fc4df40d4 100644 --- a/packages/ui/certd-client/src/api/service.ts +++ b/packages/ui/certd-client/src/api/service.ts @@ -71,7 +71,7 @@ function createService() { // @ts-ignore response.config.onError(err); } - errorCreate(`${errorMessage}: ${response.config.url}`, showErrorNotify, dataAxios); + errorCreate(`${errorMessage} (请求接口: ${response.config.url})`, showErrorNotify, dataAxios); } }, error => { @@ -113,7 +113,7 @@ function createService() { default: break; } - error.message += `: ${error.response?.config?.url}`; + error.message += `( 请求接口:${error.response?.config?.url})`; errorLog(error, error?.response?.config?.showErrorNotify); if (status === 401) { const userStore = useUserStore(); diff --git a/packages/ui/certd-client/src/locales/langs/en-US/certd.ts b/packages/ui/certd-client/src/locales/langs/en-US/certd.ts index 1294223d7..6823f0e1e 100644 --- a/packages/ui/certd-client/src/locales/langs/en-US/certd.ts +++ b/packages/ui/certd-client/src/locales/langs/en-US/certd.ts @@ -52,6 +52,7 @@ export default { siteMonitorSetting: "Site Monitor Settings", userSecurity: "Security Settings", userProfile: "Account Info", + userGrant: "Grant Delegation", suite: "Suite", mySuite: "My Suite", suiteBuy: "Suite Purchase", @@ -62,6 +63,12 @@ export default { greeting: "Hello", profile: "Account Info", logout: "Logout", + setting: { + grantSetting: "Grant Settings", + saveSuccess: "Save Success", + allowAdminViewCerts: "Allow Admin view and download Certs", + allowAdminViewCertsHelper: "Allow admin view and download all certificates", + }, }, dashboard: { greeting: "Hello, {name}, welcome to 【{site}】", diff --git a/packages/ui/certd-client/src/locales/langs/zh-CN/certd.ts b/packages/ui/certd-client/src/locales/langs/zh-CN/certd.ts index c7cb5f34c..62528178c 100644 --- a/packages/ui/certd-client/src/locales/langs/zh-CN/certd.ts +++ b/packages/ui/certd-client/src/locales/langs/zh-CN/certd.ts @@ -57,6 +57,7 @@ export default { siteMonitorSetting: "站点监控设置", userSecurity: "认证安全设置", userProfile: "账号信息", + userGrant: "授权委托", suite: "套餐", mySuite: "我的套餐", suiteBuy: "套餐购买", @@ -68,6 +69,13 @@ export default { greeting: "您好", profile: "账号信息", logout: "注销登录", + + setting: { + grantSetting: "授权委托设置", + saveSuccess: "保存成功", + allowAdminViewCerts: "授权管理员查看和下载证书", + allowAdminViewCertsHelper: "允许管理员查看和下载我的所有证书", + }, }, dashboard: { greeting: "您好,{name},欢迎使用 【{site}】", diff --git a/packages/ui/certd-client/src/router/source/modules/certd.ts b/packages/ui/certd-client/src/router/source/modules/certd.ts index bba7fae8e..c14e7432e 100644 --- a/packages/ui/certd-client/src/router/source/modules/certd.ts +++ b/packages/ui/certd-client/src/router/source/modules/certd.ts @@ -204,6 +204,17 @@ export const certdResources = [ isMenu: true, }, }, + { + title: "certd.userGrant", + name: "UserGrantSetting", + path: "/certd/mine/grant", + component: "/certd/mine/grant/index.vue", + meta: { + icon: "mi:user-check", + auth: true, + isMenu: true, + }, + }, { title: "certd.userProfile", name: "UserProfile", diff --git a/packages/ui/certd-client/src/views/certd/mine/change-password-button.vue b/packages/ui/certd-client/src/views/certd/mine/change-password-button.vue index b6615fbef..a1b530de6 100644 --- a/packages/ui/certd-client/src/views/certd/mine/change-password-button.vue +++ b/packages/ui/certd-client/src/views/certd/mine/change-password-button.vue @@ -1,6 +1,6 @@ - {{ $t("authentication.changePasswordButton") }} + {{ t("authentication.changePasswordButton") }} diff --git a/packages/ui/certd-client/src/views/certd/mine/grant/api.ts b/packages/ui/certd-client/src/views/certd/mine/grant/api.ts new file mode 100644 index 000000000..6ca864091 --- /dev/null +++ b/packages/ui/certd-client/src/views/certd/mine/grant/api.ts @@ -0,0 +1,25 @@ +// @ts-ignore +import { request } from "/@/api/service"; +const apiPrefix = "/user/settings"; +export type UserGrantSetting = { + allowAdminViewCerts: boolean; +}; + +export async function GrantSettingsGet() { + const res = await request({ + url: apiPrefix + "/grant/get", + method: "post", + }); + if (!res) { + return {}; + } + return res as UserGrantSetting; +} + +export async function UserSettingSave(req: any) { + return await request({ + url: apiPrefix + "/grant/save", + method: "post", + data: req, + }); +} diff --git a/packages/ui/certd-client/src/views/certd/mine/grant/index.vue b/packages/ui/certd-client/src/views/certd/mine/grant/index.vue new file mode 100644 index 000000000..3da78c012 --- /dev/null +++ b/packages/ui/certd-client/src/views/certd/mine/grant/index.vue @@ -0,0 +1,67 @@ + + + + {{ t("certd.user.setting.grantSetting") }} + + + + + + + + + + {{ t("certd.user.setting.allowAdminViewCertsHelper") }} + + + + {{ t("certd.confirm") }} + + + + + + + + + diff --git a/packages/ui/certd-server/src/controller/user/mine/user-settings-controller.ts b/packages/ui/certd-server/src/controller/user/mine/user-settings-controller.ts index db2a3a296..efa813a6c 100644 --- a/packages/ui/certd-server/src/controller/user/mine/user-settings-controller.ts +++ b/packages/ui/certd-server/src/controller/user/mine/user-settings-controller.ts @@ -2,6 +2,9 @@ import { ALL, Body, Controller, Inject, Post, Provide, Query } from "@midwayjs/c import { Constants, CrudController } from "@certd/lib-server"; import { UserSettingsService } from "../../../modules/mine/service/user-settings-service.js"; import { UserSettingsEntity } from "../../../modules/mine/entity/user-settings.js"; +import { UserGrantSetting } from "../../../modules/mine/service/models.js"; +import { isPlus } from "@certd/plus-core"; +import { merge } from "lodash-es"; /** */ @@ -65,6 +68,26 @@ export class UserSettingsController extends CrudController const entity = await this.service.getByKey(key, this.getUserId()); return this.ok(entity); } +@Post("/grant/get", { summary: Constants.per.authOnly }) + async grantSettingsGet() { + const userId = this.getUserId(); + const setting = await this.service.getSetting(userId, UserGrantSetting); + return this.ok(setting); + } + + @Post("/grant/save", { summary: Constants.per.authOnly }) + async grantSettingsSave(@Body(ALL) bean: UserGrantSetting) { + if (!isPlus()) { + throw new Error('本功能需要开通专业版') + } + const userId = this.getUserId(); + const setting = new UserGrantSetting(); + merge(setting, bean); + + await this.service.saveSetting(userId, setting); + return this.ok({}); + } + } diff --git a/packages/ui/certd-server/src/controller/user/pipeline/cert-controller.ts b/packages/ui/certd-server/src/controller/user/pipeline/cert-controller.ts index 200c550dc..c723c5d1e 100644 --- a/packages/ui/certd-server/src/controller/user/pipeline/cert-controller.ts +++ b/packages/ui/certd-server/src/controller/user/pipeline/cert-controller.ts @@ -1,8 +1,10 @@ -import {Body, Controller, Inject, Post, Provide, Query} from '@midwayjs/core'; +import { Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core'; import { PipelineService } from '../../../modules/pipeline/service/pipeline-service.js'; -import { BaseController, Constants } from '@certd/lib-server'; +import { BaseController, Constants, PermissionException } from '@certd/lib-server'; import { StorageService } from '../../../modules/pipeline/service/storage-service.js'; -import {CertReader} from "@certd/plugin-cert"; +import { CertReader } from "@certd/plugin-cert"; +import { UserSettingsService } from '../../../modules/mine/service/user-settings-service.js'; +import { UserGrantSetting } from '../../../modules/mine/service/models.js'; @Provide() @Controller('/api/pi/cert') @@ -12,10 +14,32 @@ export class CertController extends BaseController { @Inject() storeService: StorageService; + + @Inject() + userSettingsService: UserSettingsService; + + @Post('/get', { summary: Constants.per.authOnly }) async getCert(@Query('id') id: number) { const userId = this.getUserId(); - await this.pipelineService.checkUserId(id, userId); + + + + const pipleinUserId = await this.pipelineService.getPipelineUserId(id); + + if (pipleinUserId !== userId) { + // 如果是管理员,检查用户是否有授权管理员查看 + const isAdmin = await this.isAdmin() + if (!isAdmin) { + throw new PermissionException(); + } + // 是否允许管理员查看 + const setting = await this.userSettingsService.getSetting(pipleinUserId, UserGrantSetting, false); + if (setting?.allowAdminViewCerts !== true) { + //不允许管理员查看 + throw new PermissionException("该流水线的用户还未授权管理员查看证书,请先让用户在”设置->授权委托“中打开开关"); + } + } const privateVars = await this.storeService.getPipelinePrivateVars(id); return this.ok(privateVars.cert); } @@ -24,7 +48,7 @@ export class CertController extends BaseController { @Post('/readCertDetail', { summary: Constants.per.authOnly }) async readCertDetail(@Body('crt') crt: string) { if (!crt) { - throw new Error('crt is required'); + throw new Error('crt is required'); } const certDetail = CertReader.readCertDetail(crt) return this.ok(certDetail); diff --git a/packages/ui/certd-server/src/controller/user/pipeline/history-controller.ts b/packages/ui/certd-server/src/controller/user/pipeline/history-controller.ts index f453b542f..9e8076c76 100644 --- a/packages/ui/certd-server/src/controller/user/pipeline/history-controller.ts +++ b/packages/ui/certd-server/src/controller/user/pipeline/history-controller.ts @@ -10,6 +10,8 @@ import * as fs from "fs"; import { logger } from "@certd/basic"; import { AuthService } from "../../../modules/sys/authority/service/auth-service.js"; import { In } from "typeorm"; +import { UserSettingsService } from "../../../modules/mine/service/user-settings-service.js"; +import { UserGrantSetting } from "../../../modules/mine/service/models.js"; /** * 证书 @@ -30,6 +32,9 @@ export class HistoryController extends CrudController { @Inject() sysSettingsService: SysSettingsService; + @Inject() + userSettingsService: UserSettingsService; + getService(): HistoryService { return this.service; } @@ -77,7 +82,7 @@ export class HistoryController extends CrudController { @Post('/list', { summary: Constants.per.authOnly }) async list(@Body(ALL) body) { - const isAdmin = await this.authService.isAdmin(this.ctx); + const isAdmin = this.authService.isAdmin(this.ctx); if (!isAdmin) { body.userId = this.getUserId(); } @@ -89,7 +94,7 @@ export class HistoryController extends CrudController { }; const withDetail = body.withDetail; delete body.withDetail; - let select:any = null + let select: any = null if (!withDetail) { select = { pipeline: true, // 后面这里改成false @@ -193,7 +198,6 @@ export class HistoryController extends CrudController { @Post('/files', { summary: Constants.per.authOnly }) async files(@Query('pipelineId') pipelineId: number, @Query('historyId') historyId: number) { - await this.authService.checkEntityUserId(this.ctx, this.service, historyId); const files = await this.getFiles(historyId, pipelineId); return this.ok(files); } @@ -210,14 +214,24 @@ export class HistoryController extends CrudController { throw new CommonException('historyId is null'); } if (history.userId !== this.getUserId()) { - throw new PermissionException(); + // 如果是管理员,检查用户是否有授权管理员查看 + const isAdmin = await this.isAdmin() + if (!isAdmin) { + throw new PermissionException(); + } + // 是否允许管理员查看 + const setting = await this.userSettingsService.getSetting(history.userId, UserGrantSetting, false); + if (setting?.allowAdminViewCerts!==true) { + //不允许管理员查看 + throw new PermissionException("该流水线的用户还未授权管理员下载证书,请先让用户在”设置->授权委托“中打开开关"); + } + //允许管理员查看 } return await this.service.getFiles(history); } @Get('/download', { summary: Constants.per.authOnly }) async download(@Query('pipelineId') pipelineId: number, @Query('historyId') historyId: number, @Query('fileId') fileId: string) { - await this.authService.checkEntityUserId(this.ctx, this.service, historyId); const files = await this.getFiles(historyId, pipelineId); const file = files.find(f => f.id === fileId); if (file == null) { diff --git a/packages/ui/certd-server/src/modules/mine/service/models.ts b/packages/ui/certd-server/src/modules/mine/service/models.ts index fc8ce6ca6..5b49ade16 100644 --- a/packages/ui/certd-server/src/modules/mine/service/models.ts +++ b/packages/ui/certd-server/src/modules/mine/service/models.ts @@ -37,3 +37,12 @@ export class UserEmailSetting extends BaseSettings { list:string[] = []; } + + + +export class UserGrantSetting extends BaseSettings { + static __title__ = "用户授权设置"; + static __key__ = "user.grant"; + + allowAdminViewCerts:boolean = false; +} diff --git a/packages/ui/certd-server/src/modules/pipeline/service/pipeline-service.ts b/packages/ui/certd-server/src/modules/pipeline/service/pipeline-service.ts index d273d6620..e5d463913 100644 --- a/packages/ui/certd-server/src/modules/pipeline/service/pipeline-service.ts +++ b/packages/ui/certd-server/src/modules/pipeline/service/pipeline-service.ts @@ -1072,4 +1072,16 @@ export class PipelineService extends BaseService { }); return res?.status; } + + async getPipelineUserId(pipelineId: number) { + const res = await this.repository.findOne({ + select: { + userId: true + }, + where: { + id: pipelineId + } + }); + return res?.userId; + } }