diff --git a/ui/packages/tidb-dashboard-client/src/client/api/api/default-api.ts b/ui/packages/tidb-dashboard-client/src/client/api/api/default-api.ts index 2304912f1a..3c8d4c15e5 100644 --- a/ui/packages/tidb-dashboard-client/src/client/api/api/default-api.ts +++ b/ui/packages/tidb-dashboard-client/src/client/api/api/default-api.ts @@ -3873,6 +3873,39 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati options: localVarRequestOptions, }; }, + /** + * + * @summary Reset encryption key to revoke all authorized codes + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + userRevokeSession: async (options: AxiosRequestConfig = {}): Promise => { + const localVarPath = `/user/share/revoke`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication JwtAuth required + await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration) + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, /** * * @summary Create an impersonation @@ -5217,6 +5250,16 @@ export const DefaultApiFp = function(configuration?: Configuration) { const localVarAxiosArgs = await localVarAxiosParamCreator.userLogin(message, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, + /** + * + * @summary Reset encryption key to revoke all authorized codes + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async userRevokeSession(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.userRevokeSession(options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, /** * * @summary Create an impersonation @@ -6274,6 +6317,15 @@ export const DefaultApiFactory = function (configuration?: Configuration, basePa userLogin(message: UserAuthenticateForm, options?: any): AxiosPromise { return localVarFp.userLogin(message, options).then((request) => request(axios, basePath)); }, + /** + * + * @summary Reset encryption key to revoke all authorized codes + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + userRevokeSession(options?: any): AxiosPromise { + return localVarFp.userRevokeSession(options).then((request) => request(axios, basePath)); + }, /** * * @summary Create an impersonation @@ -8716,6 +8768,17 @@ export class DefaultApi extends BaseAPI { return DefaultApiFp(this.configuration).userLogin(requestParameters.message, options).then((request) => request(this.axios, this.basePath)); } + /** + * + * @summary Reset encryption key to revoke all authorized codes + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof DefaultApi + */ + public userRevokeSession(options?: AxiosRequestConfig) { + return DefaultApiFp(this.configuration).userRevokeSession(options).then((request) => request(this.axios, this.basePath)); + } + /** * * @summary Create an impersonation diff --git a/ui/packages/tidb-dashboard-client/swagger/spec.json b/ui/packages/tidb-dashboard-client/swagger/spec.json index a3722345d3..9d923b210c 100644 --- a/ui/packages/tidb-dashboard-client/swagger/spec.json +++ b/ui/packages/tidb-dashboard-client/swagger/spec.json @@ -3631,6 +3631,22 @@ } } }, + "/user/share/revoke": { + "post": { + "security": [ + { + "JwtAuth": [] + } + ], + "summary": "Reset encryption key to revoke all authorized codes", + "operationId": "userRevokeSession", + "responses": { + "200": { + "description": "" + } + } + } + }, "/user/sign_out_info": { "get": { "security": [ diff --git a/ui/packages/tidb-dashboard-for-clinic-cloud/src/apps/UserProfile/context.ts b/ui/packages/tidb-dashboard-for-clinic-cloud/src/apps/UserProfile/context.ts index d3dcf52818..ad536a3450 100644 --- a/ui/packages/tidb-dashboard-for-clinic-cloud/src/apps/UserProfile/context.ts +++ b/ui/packages/tidb-dashboard-for-clinic-cloud/src/apps/UserProfile/context.ts @@ -39,6 +39,11 @@ class DataSource implements IUserProfileDataSource { userShareSession(request: CodeShareRequest, options?: ReqConfig) { return client.getInstance().userShareSession({ request }, options) } + + userRevokeSession(options?: ReqConfig) { + return client.getInstance().userRevokeSession(options) + } + metricsGetPromAddress(options?: ReqConfig) { return client.getInstance().metricsGetPromAddress(options) } diff --git a/ui/packages/tidb-dashboard-for-op/src/apps/UserProfile/context.ts b/ui/packages/tidb-dashboard-for-op/src/apps/UserProfile/context.ts index ed103e515e..3d3b0d4379 100644 --- a/ui/packages/tidb-dashboard-for-op/src/apps/UserProfile/context.ts +++ b/ui/packages/tidb-dashboard-for-op/src/apps/UserProfile/context.ts @@ -40,6 +40,11 @@ class DataSource implements IUserProfileDataSource { userShareSession(request: CodeShareRequest, options?: ReqConfig) { return client.getInstance().userShareSession({ request }, options) } + + userRevokeSession(options?: ReqConfig) { + return client.getInstance().userRevokeSession(options) + } + metricsGetPromAddress(options?: ReqConfig) { return client.getInstance().metricsGetPromAddress(options) } diff --git a/ui/packages/tidb-dashboard-lib/src/apps/UserProfile/components/Form.Session.tsx b/ui/packages/tidb-dashboard-lib/src/apps/UserProfile/components/Form.Session.tsx index 8d61cfbd90..80c4363cd7 100644 --- a/ui/packages/tidb-dashboard-lib/src/apps/UserProfile/components/Form.Session.tsx +++ b/ui/packages/tidb-dashboard-lib/src/apps/UserProfile/components/Form.Session.tsx @@ -4,6 +4,7 @@ import { CopyOutlined, LogoutOutlined, QuestionCircleOutlined, + RollbackOutlined, ShareAltOutlined } from '@ant-design/icons' import { @@ -11,6 +12,7 @@ import { Button, Divider, Form, + message, Modal, Select, Space, @@ -40,6 +42,46 @@ const SHARE_SESSION_EXPIRY_HOURS = [ 24 * 30 ] +function RevokeSessionButton() { + const whoAmI = store.useState((s) => s.whoAmI) + const { t } = useTranslation() + const ctx = useContext(UserProfileContext) + + function showRevokeConfirm() { + Modal.confirm({ + title: t('user_profile.revoke_modal.title'), + content: t('user_profile.revoke_modal.content'), + okText: t('user_profile.revoke_modal.ok'), + cancelText: t('user_profile.revoke_modal.cancel'), + onOk() { + ctx?.ds.userRevokeSession().then(() => { + message.success(t('user_profile.revoke_modal.success_message')) + }) + } + }) + } + + let button = ( + + ) + + if (whoAmI && !whoAmI.is_shareable) { + button = ( + + {button} + + ) + } + + return <>{button} +} + function ShareSessionButton() { const ctx = useContext(UserProfileContext) @@ -143,11 +185,6 @@ function ShareSessionButton() { width={600} > {t('user_profile.share_session.text')} -
+ {/* only available for v8.4.0+, v6.5.11+ */} + diff --git a/ui/packages/tidb-dashboard-lib/src/apps/UserProfile/context/index.ts b/ui/packages/tidb-dashboard-lib/src/apps/UserProfile/context/index.ts index f89757521d..cc37f397b3 100644 --- a/ui/packages/tidb-dashboard-lib/src/apps/UserProfile/context/index.ts +++ b/ui/packages/tidb-dashboard-lib/src/apps/UserProfile/context/index.ts @@ -44,6 +44,8 @@ export interface IUserProfileDataSource { options?: ReqConfig ): AxiosPromise + userRevokeSession(options?: ReqConfig): AxiosPromise + metricsGetPromAddress( options?: ReqConfig ): AxiosPromise diff --git a/ui/packages/tidb-dashboard-lib/src/apps/UserProfile/translations/en.yaml b/ui/packages/tidb-dashboard-lib/src/apps/UserProfile/translations/en.yaml index 484cd04808..aadc46b8b5 100755 --- a/ui/packages/tidb-dashboard-lib/src/apps/UserProfile/translations/en.yaml +++ b/ui/packages/tidb-dashboard-lib/src/apps/UserProfile/translations/en.yaml @@ -50,6 +50,8 @@ user_profile: sign_out: Sign Out share: Share Current Session share_unavailable_tooltip: Current session is not allowed to be shared + revoke: Revoke Authorization Codes + revoke_unavailable_tooltip: You have no permission to revoke the authorization codes share_session: text: > You can invite others to access this {{distro.tidb}} Dashboard by sharing your @@ -57,12 +59,11 @@ user_profile: - The Authorization Code can be used multiple times. + - The shared session has the same privilege as your current session. + - The shared session will be invalidated after the expiry time you specified. - - The shared session has the same privilege as your current session. - warning: > - Warning: Shared session will remain valid and cannot be revoked until it is expired. - Keep the Authorization Code safe! + - The shared session can be revoked in advance by administrator. form: expire: Expire in read_only: Share as read-only privilege @@ -72,6 +73,12 @@ user_profile: title: Authorization Code Generated copy: Copy copied: Copied + revoke_modal: + title: Are you sure you want to revoke all authorization codes? + content: After revoking, all authorization codes that are authorized before can't be used to login again, and this action can't undo. + ok: Revoke + cancel: Cancel + success_message: Revoke authorization codes successfully! version: title: Version Information internal_version: '{{distro.tidb}} Dashboard Internal Version' diff --git a/ui/packages/tidb-dashboard-lib/src/apps/UserProfile/translations/zh.yaml b/ui/packages/tidb-dashboard-lib/src/apps/UserProfile/translations/zh.yaml index 9f1828eb95..7745df2c30 100755 --- a/ui/packages/tidb-dashboard-lib/src/apps/UserProfile/translations/zh.yaml +++ b/ui/packages/tidb-dashboard-lib/src/apps/UserProfile/translations/zh.yaml @@ -50,17 +50,19 @@ user_profile: sign_out: 登出 share: 分享当前会话 share_unavailable_tooltip: 当前会话被禁止分享 + revoke: 撤消授权码 + revoke_unavailable_tooltip: 你没有权限撤消授权码 share_session: text: > - 您可以生成一个**授权码**来将您当前的会话分享给其他人、邀请他们使用该 {{distro.tidb}} Dashboard: + 您可以生成一个**授权码**来将您当前的会话分享给其他人,邀请他们使用该 {{distro.tidb}} Dashboard: - 授权码可以被重复使用。 + - 分享的会话和您当前会话具有相同权限。 + - 分享的会话将在您指定的有效时间后过期。 - - 分享的会话和您当前会话具有相同权限。 - warning: > - 警告:已分享的会话无法被提前注销,将保持有效直到有效时间过期,因此请妥善保管授权码。 + - 分享的会话可以被管理员提前撤消。 form: expire: 有效时间 read_only: 以只读权限分享 @@ -70,6 +72,12 @@ user_profile: title: 授权码已生成 copy: 复制 copied: 已复制 + revoke_modal: + title: 你确定你要撤消所有的授权码吗? + content: 撤消之后,所有之前授权的授权码都不能再用于登录,而且这个操作不能回滚。 + ok: 撤消 + cancel: 取消 + success_message: 撤消授权码成功! version: title: 版本信息 internal_version: '{{distro.tidb}} Dashboard 内部版本号'