From f07c09b24350d33c4b1ad5d3d20bb994dfdfaec4 Mon Sep 17 00:00:00 2001 From: guqing <38999863+guqing@users.noreply.github.com> Date: Sun, 21 Apr 2024 15:07:46 +0800 Subject: [PATCH] feat: add original password verification for password change (#5748) * feat: add original password verification for password change * chore: update properties file * Refine ui Signed-off-by: Ryan Wang * chore: update properties file * fix: confirm assword * fix: unit test case * feat: add new api for change own password * chore: regenerate api client * chore: adapt to UI * chore: enusre old password not blank --------- Signed-off-by: Ryan Wang Co-authored-by: Ryan Wang --- api-docs/openapi/v3_0/aggregated.json | 61 +++++++- .../core/extension/endpoint/UserEndpoint.java | 53 ++++++- .../core/extension/service/UserService.java | 2 + .../extension/service/UserServiceImpl.java | 17 +++ .../resources/config/i18n/messages.properties | 1 + .../config/i18n/messages_zh.properties | 1 + .../extension/endpoint/UserEndpointTest.java | 10 +- .../service/UserServiceImplTest.java | 17 +++ .../components/UserPasswordChangeModal.vue | 2 +- .../api-client/src/.openapi-generator/FILES | 1 + .../api-console-halo-run-v1alpha1-user-api.ts | 133 +++++++++++++++--- .../src/models/change-own-password-request.ts | 36 +++++ ui/packages/api-client/src/models/index.ts | 1 + ui/src/locales/en.yaml | 12 +- ui/src/locales/zh-CN.yaml | 2 + ui/src/locales/zh-TW.yaml | 2 + .../components/PasswordChangeModal.vue | 19 ++- 17 files changed, 329 insertions(+), 41 deletions(-) create mode 100644 ui/packages/api-client/src/models/change-own-password-request.ts diff --git a/api-docs/openapi/v3_0/aggregated.json b/api-docs/openapi/v3_0/aggregated.json index a78e927273..07cbaf78ca 100644 --- a/api-docs/openapi/v3_0/aggregated.json +++ b/api-docs/openapi/v3_0/aggregated.json @@ -4173,6 +4173,37 @@ ] } }, + "/apis/api.console.halo.run/v1alpha1/users/-/password": { + "put": { + "description": "Change own password of user.", + "operationId": "ChangeOwnPassword", + "requestBody": { + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ChangeOwnPasswordRequest" + } + } + }, + "required": true + }, + "responses": { + "default": { + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "description": "default response" + } + }, + "tags": [ + "api.console.halo.run/v1alpha1/User" + ] + } + }, "/apis/api.console.halo.run/v1alpha1/users/-/send-email-verification-code": { "post": { "description": "Send email verification code for user", @@ -4329,8 +4360,8 @@ }, "/apis/api.console.halo.run/v1alpha1/users/{name}/password": { "put": { - "description": "Change password of user.", - "operationId": "ChangePassword", + "description": "Change anyone password of user for admin.", + "operationId": "ChangeAnyonePassword", "parameters": [ { "description": "Name of user. If the name is equal to \u0027-\u0027, it will change the password of current user.", @@ -13152,6 +13183,24 @@ } } }, + "ChangeOwnPasswordRequest": { + "required": [ + "oldPassword", + "password" + ], + "type": "object", + "properties": { + "oldPassword": { + "type": "string", + "description": "Old password." + }, + "password": { + "minLength": 6, + "type": "string", + "description": "New password." + } + } + }, "ChangePasswordRequest": { "required": [ "password" @@ -16913,12 +16962,12 @@ }, "visible": { "type": "string", + "default": "PUBLIC", "enum": [ "PUBLIC", "INTERNAL", "PRIVATE" - ], - "default": "PUBLIC" + ] } } }, @@ -18531,12 +18580,12 @@ }, "visible": { "type": "string", + "default": "PUBLIC", "enum": [ "PUBLIC", "INTERNAL", "PRIVATE" - ], - "default": "PUBLIC" + ] } } }, diff --git a/application/src/main/java/run/halo/app/core/extension/endpoint/UserEndpoint.java b/application/src/main/java/run/halo/app/core/extension/endpoint/UserEndpoint.java index a2f9154055..0f7c71baec 100644 --- a/application/src/main/java/run/halo/app/core/extension/endpoint/UserEndpoint.java +++ b/application/src/main/java/run/halo/app/core/extension/endpoint/UserEndpoint.java @@ -89,6 +89,7 @@ import run.halo.app.infra.SystemSetting; import run.halo.app.infra.ValidationUtils; import run.halo.app.infra.exception.RateLimitExceededException; +import run.halo.app.infra.exception.UnsatisfiedAttributeValueException; import run.halo.app.infra.utils.JsonUtils; import run.halo.app.security.authentication.twofactor.TwoFactorAuthentication; @@ -160,9 +161,19 @@ public RouterFunction endpoint() { .description("User name") .required(true)) .response(responseBuilder().implementation(UserPermission.class))) - .PUT("/users/{name}/password", this::changePassword, - builder -> builder.operationId("ChangePassword") - .description("Change password of user.") + .PUT("/users/-/password", this::changeOwnPassword, + builder -> builder.operationId("ChangeOwnPassword") + .description("Change own password of user.") + .tag(tag) + .requestBody(requestBodyBuilder() + .required(true) + .implementation(ChangeOwnPasswordRequest.class)) + .response(responseBuilder() + .implementation(User.class)) + ) + .PUT("/users/{name}/password", this::changeAnyonePasswordForAdmin, + builder -> builder.operationId("ChangeAnyonePassword") + .description("Change anyone password of user for admin.") .tag(tag) .parameter(parameterBuilder().in(ParameterIn.PATH).name("name") .description( @@ -520,7 +531,7 @@ private Mono updateProfile(ServerRequest request) { .flatMap(updatedUser -> ServerResponse.ok().bodyValue(updatedUser)); } - Mono changePassword(ServerRequest request) { + Mono changeAnyonePasswordForAdmin(ServerRequest request) { final var nameInPath = request.pathVariable("name"); return ReactiveSecurityContextHolder.getContext() .map(ctx -> SELF_USER.equals(nameInPath) ? ctx.getAuthentication().getName() @@ -538,6 +549,40 @@ Mono changePassword(ServerRequest request) { .bodyValue(updatedUser)); } + Mono changeOwnPassword(ServerRequest request) { + return ReactiveSecurityContextHolder.getContext() + .map(ctx -> ctx.getAuthentication().getName()) + .flatMap(username -> request.bodyToMono(ChangeOwnPasswordRequest.class) + .switchIfEmpty(Mono.defer(() -> + Mono.error(new ServerWebInputException("Request body is empty")))) + .flatMap(changePasswordRequest -> { + var rawOldPassword = changePasswordRequest.oldPassword(); + return userService.confirmPassword(username, rawOldPassword) + .filter(Boolean::booleanValue) + .switchIfEmpty(Mono.error(new UnsatisfiedAttributeValueException( + "Old password is incorrect.", + "problemDetail.user.oldPassword.notMatch", + null)) + ) + .thenReturn(changePasswordRequest); + }) + .flatMap(changePasswordRequest -> { + var password = changePasswordRequest.password(); + // encode password + return userService.updateWithRawPassword(username, password); + })) + .flatMap(updatedUser -> ServerResponse.ok() + .contentType(MediaType.APPLICATION_JSON) + .bodyValue(updatedUser)); + } + + record ChangeOwnPasswordRequest( + @Schema(description = "Old password.", requiredMode = REQUIRED) + String oldPassword, + @Schema(description = "New password.", requiredMode = REQUIRED, minLength = 6) + String password) { + } + record ChangePasswordRequest( @Schema(description = "New password.", requiredMode = REQUIRED, minLength = 6) String password) { diff --git a/application/src/main/java/run/halo/app/core/extension/service/UserService.java b/application/src/main/java/run/halo/app/core/extension/service/UserService.java index ad81163eba..55337910d4 100644 --- a/application/src/main/java/run/halo/app/core/extension/service/UserService.java +++ b/application/src/main/java/run/halo/app/core/extension/service/UserService.java @@ -23,4 +23,6 @@ public interface UserService { Mono signUp(User user, String password); Mono createUser(User user, Set roles); + + Mono confirmPassword(String username, String rawPassword); } diff --git a/application/src/main/java/run/halo/app/core/extension/service/UserServiceImpl.java b/application/src/main/java/run/halo/app/core/extension/service/UserServiceImpl.java index 97672c524b..50c20bce63 100644 --- a/application/src/main/java/run/halo/app/core/extension/service/UserServiceImpl.java +++ b/application/src/main/java/run/halo/app/core/extension/service/UserServiceImpl.java @@ -176,4 +176,21 @@ public Mono createUser(User user, Set roleNames) { .flatMap(newUser -> grantRoles(user.getMetadata().getName(), roleNames))) ); } + + @Override + public Mono confirmPassword(String username, String rawPassword) { + + return getUser(username) + .filter(user -> { + if (!StringUtils.hasText(user.getSpec().getPassword())) { + // If the password is not set, return true directly. + return true; + } + if (!StringUtils.hasText(rawPassword)) { + return false; + } + return passwordEncoder.matches(rawPassword, user.getSpec().getPassword()); + }) + .hasElement(); + } } diff --git a/application/src/main/resources/config/i18n/messages.properties b/application/src/main/resources/config/i18n/messages.properties index 3be011e083..ef743089a5 100644 --- a/application/src/main/resources/config/i18n/messages.properties +++ b/application/src/main/resources/config/i18n/messages.properties @@ -51,6 +51,7 @@ problemDetail.index.duplicateKey=The value of {0} already exists for unique inde problemDetail.user.email.verify.maxAttempts=Too many verification attempts, please try again later. problemDetail.user.password.unsatisfied=The password does not meet the specifications. problemDetail.user.username.unsatisfied=The username does not meet the specifications. +problemDetail.user.oldPassword.notMatch=The old password does not match. problemDetail.user.signUpFailed.disallowed=System does not allow new users to register. problemDetail.user.duplicateName=The username {0} already exists, please rename it and retry. problemDetail.comment.turnedOff=The comment function has been turned off. diff --git a/application/src/main/resources/config/i18n/messages_zh.properties b/application/src/main/resources/config/i18n/messages_zh.properties index 7ae8650cc2..46d7ab069a 100644 --- a/application/src/main/resources/config/i18n/messages_zh.properties +++ b/application/src/main/resources/config/i18n/messages_zh.properties @@ -28,6 +28,7 @@ problemDetail.index.duplicateKey=唯一索引 {1} 中的值 {0} 已存在,请 problemDetail.user.email.verify.maxAttempts=尝试次数过多,请稍候再试。 problemDetail.user.password.unsatisfied=密码不符合规范。 problemDetail.user.username.unsatisfied=用户名不符合规范。 +problemDetail.user.oldPassword.notMatch=旧密码不匹配。 problemDetail.user.signUpFailed.disallowed=系统不允许注册新用户。 problemDetail.user.duplicateName=用户名 {0} 已存在,请更换用户名后重试。 problemDetail.plugin.version.unsatisfied.requires=插件要求一个最小的系统版本为 {0}, 但当前版本为 {1}。 diff --git a/application/src/test/java/run/halo/app/core/extension/endpoint/UserEndpointTest.java b/application/src/test/java/run/halo/app/core/extension/endpoint/UserEndpointTest.java index f33612406e..0b05a51a1b 100644 --- a/application/src/test/java/run/halo/app/core/extension/endpoint/UserEndpointTest.java +++ b/application/src/test/java/run/halo/app/core/extension/endpoint/UserEndpointTest.java @@ -306,8 +306,11 @@ void shouldUpdateMyPasswordCorrectly() { var user = new User(); when(userService.updateWithRawPassword("fake-user", "new-password")) .thenReturn(Mono.just(user)); + when(userService.confirmPassword("fake-user", "old-password")) + .thenReturn(Mono.just(true)); webClient.put().uri("/users/-/password") - .bodyValue(new UserEndpoint.ChangePasswordRequest("new-password")) + .bodyValue( + new UserEndpoint.ChangeOwnPasswordRequest("old-password", "new-password")) .exchange() .expectStatus().isOk() .expectBody(User.class) @@ -319,11 +322,14 @@ void shouldUpdateMyPasswordCorrectly() { @Test void shouldUpdateOtherPasswordCorrectly() { var user = new User(); + when(userService.confirmPassword("another-fake-user", "old-password")) + .thenReturn(Mono.just(true)); when(userService.updateWithRawPassword("another-fake-user", "new-password")) .thenReturn(Mono.just(user)); webClient.put() .uri("/users/another-fake-user/password") - .bodyValue(new UserEndpoint.ChangePasswordRequest("new-password")) + .bodyValue( + new UserEndpoint.ChangeOwnPasswordRequest("old-password", "new-password")) .exchange() .expectStatus().isOk() .expectBody(User.class) diff --git a/application/src/test/java/run/halo/app/core/extension/service/UserServiceImplTest.java b/application/src/test/java/run/halo/app/core/extension/service/UserServiceImplTest.java index a3002641b4..e7ee9b1e2c 100644 --- a/application/src/test/java/run/halo/app/core/extension/service/UserServiceImplTest.java +++ b/application/src/test/java/run/halo/app/core/extension/service/UserServiceImplTest.java @@ -485,4 +485,21 @@ User fakeSignUpUser(String name, String password) { return user; } } + + @Test + void confirmPasswordWhenPasswordNotSet() { + var user = new User(); + user.setSpec(new User.UserSpec()); + when(client.get(User.class, "fake-user")).thenReturn(Mono.just(user)); + userService.confirmPassword("fake-user", "fake-password") + .as(StepVerifier::create) + .expectNext(true) + .verifyComplete(); + + user.getSpec().setPassword(""); + userService.confirmPassword("fake-user", "fake-password") + .as(StepVerifier::create) + .expectNext(true) + .verifyComplete(); + } } diff --git a/ui/console-src/modules/system/users/components/UserPasswordChangeModal.vue b/ui/console-src/modules/system/users/components/UserPasswordChangeModal.vue index daeb188f05..569f587d54 100644 --- a/ui/console-src/modules/system/users/components/UserPasswordChangeModal.vue +++ b/ui/console-src/modules/system/users/components/UserPasswordChangeModal.vue @@ -67,7 +67,7 @@ const handleChangePassword = async () => { const changePasswordRequest = cloneDeep(formState.value); delete changePasswordRequest.password_confirm; - await apiClient.user.changePassword({ + await apiClient.user.changeAnyonePassword({ name: props.user?.metadata.name || "", changePasswordRequest, }); diff --git a/ui/packages/api-client/src/.openapi-generator/FILES b/ui/packages/api-client/src/.openapi-generator/FILES index 68537e2da4..b6d2eddba2 100644 --- a/ui/packages/api-client/src/.openapi-generator/FILES +++ b/ui/packages/api-client/src/.openapi-generator/FILES @@ -100,6 +100,7 @@ models/category-status.ts models/category-vo-list.ts models/category-vo.ts models/category.ts +models/change-own-password-request.ts models/change-password-request.ts models/comment-email-owner.ts models/comment-list.ts diff --git a/ui/packages/api-client/src/api/api-console-halo-run-v1alpha1-user-api.ts b/ui/packages/api-client/src/api/api-console-halo-run-v1alpha1-user-api.ts index 7f99a3b908..b4de58cf89 100644 --- a/ui/packages/api-client/src/api/api-console-halo-run-v1alpha1-user-api.ts +++ b/ui/packages/api-client/src/api/api-console-halo-run-v1alpha1-user-api.ts @@ -22,6 +22,8 @@ import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObj // @ts-ignore import { BASE_PATH, COLLECTION_FORMATS, RequestArgs, BaseAPI, RequiredError, operationServerMap } from '../base'; // @ts-ignore +import { ChangeOwnPasswordRequest } from '../models'; +// @ts-ignore import { ChangePasswordRequest } from '../models'; // @ts-ignore import { CreateUserRequest } from '../models'; @@ -46,17 +48,17 @@ import { VerifyCodeRequest } from '../models'; export const ApiConsoleHaloRunV1alpha1UserApiAxiosParamCreator = function (configuration?: Configuration) { return { /** - * Change password of user. + * Change anyone password of user for admin. * @param {string} name Name of user. If the name is equal to \'-\', it will change the password of current user. * @param {ChangePasswordRequest} changePasswordRequest * @param {*} [options] Override http request option. * @throws {RequiredError} */ - changePassword: async (name: string, changePasswordRequest: ChangePasswordRequest, options: RawAxiosRequestConfig = {}): Promise => { + changeAnyonePassword: async (name: string, changePasswordRequest: ChangePasswordRequest, options: RawAxiosRequestConfig = {}): Promise => { // verify required parameter 'name' is not null or undefined - assertParamExists('changePassword', 'name', name) + assertParamExists('changeAnyonePassword', 'name', name) // verify required parameter 'changePasswordRequest' is not null or undefined - assertParamExists('changePassword', 'changePasswordRequest', changePasswordRequest) + assertParamExists('changeAnyonePassword', 'changePasswordRequest', changePasswordRequest) const localVarPath = `/apis/api.console.halo.run/v1alpha1/users/{name}/password` .replace(`{${"name"}}`, encodeURIComponent(String(name))); // use dummy base URL string because the URL constructor only accepts absolute URLs. @@ -92,6 +94,49 @@ export const ApiConsoleHaloRunV1alpha1UserApiAxiosParamCreator = function (confi options: localVarRequestOptions, }; }, + /** + * Change own password of user. + * @param {ChangeOwnPasswordRequest} changeOwnPasswordRequest + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + changeOwnPassword: async (changeOwnPasswordRequest: ChangeOwnPasswordRequest, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'changeOwnPasswordRequest' is not null or undefined + assertParamExists('changeOwnPassword', 'changeOwnPasswordRequest', changeOwnPasswordRequest) + const localVarPath = `/apis/api.console.halo.run/v1alpha1/users/-/password`; + // 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: 'PUT', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication BasicAuth required + // http basic authentication required + setBasicAuthToObject(localVarRequestOptions, configuration) + + // authentication BearerAuth required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(changeOwnPasswordRequest, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, /** * Creates a new user. * @param {CreateUserRequest} createUserRequest @@ -606,16 +651,28 @@ export const ApiConsoleHaloRunV1alpha1UserApiFp = function(configuration?: Confi const localVarAxiosParamCreator = ApiConsoleHaloRunV1alpha1UserApiAxiosParamCreator(configuration) return { /** - * Change password of user. + * Change anyone password of user for admin. * @param {string} name Name of user. If the name is equal to \'-\', it will change the password of current user. * @param {ChangePasswordRequest} changePasswordRequest * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async changePassword(name: string, changePasswordRequest: ChangePasswordRequest, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.changePassword(name, changePasswordRequest, options); + async changeAnyonePassword(name: string, changePasswordRequest: ChangePasswordRequest, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.changeAnyonePassword(name, changePasswordRequest, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['ApiConsoleHaloRunV1alpha1UserApi.changeAnyonePassword']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * Change own password of user. + * @param {ChangeOwnPasswordRequest} changeOwnPasswordRequest + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async changeOwnPassword(changeOwnPasswordRequest: ChangeOwnPasswordRequest, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.changeOwnPassword(changeOwnPasswordRequest, options); const localVarOperationServerIndex = configuration?.serverIndex ?? 0; - const localVarOperationServerBasePath = operationServerMap['ApiConsoleHaloRunV1alpha1UserApi.changePassword']?.[localVarOperationServerIndex]?.url; + const localVarOperationServerBasePath = operationServerMap['ApiConsoleHaloRunV1alpha1UserApi.changeOwnPassword']?.[localVarOperationServerIndex]?.url; return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); }, /** @@ -768,13 +825,22 @@ export const ApiConsoleHaloRunV1alpha1UserApiFactory = function (configuration?: const localVarFp = ApiConsoleHaloRunV1alpha1UserApiFp(configuration) return { /** - * Change password of user. - * @param {ApiConsoleHaloRunV1alpha1UserApiChangePasswordRequest} requestParameters Request parameters. + * Change anyone password of user for admin. + * @param {ApiConsoleHaloRunV1alpha1UserApiChangeAnyonePasswordRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + changeAnyonePassword(requestParameters: ApiConsoleHaloRunV1alpha1UserApiChangeAnyonePasswordRequest, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.changeAnyonePassword(requestParameters.name, requestParameters.changePasswordRequest, options).then((request) => request(axios, basePath)); + }, + /** + * Change own password of user. + * @param {ApiConsoleHaloRunV1alpha1UserApiChangeOwnPasswordRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - changePassword(requestParameters: ApiConsoleHaloRunV1alpha1UserApiChangePasswordRequest, options?: RawAxiosRequestConfig): AxiosPromise { - return localVarFp.changePassword(requestParameters.name, requestParameters.changePasswordRequest, options).then((request) => request(axios, basePath)); + changeOwnPassword(requestParameters: ApiConsoleHaloRunV1alpha1UserApiChangeOwnPasswordRequest, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.changeOwnPassword(requestParameters.changeOwnPasswordRequest, options).then((request) => request(axios, basePath)); }, /** * Creates a new user. @@ -878,26 +944,40 @@ export const ApiConsoleHaloRunV1alpha1UserApiFactory = function (configuration?: }; /** - * Request parameters for changePassword operation in ApiConsoleHaloRunV1alpha1UserApi. + * Request parameters for changeAnyonePassword operation in ApiConsoleHaloRunV1alpha1UserApi. * @export - * @interface ApiConsoleHaloRunV1alpha1UserApiChangePasswordRequest + * @interface ApiConsoleHaloRunV1alpha1UserApiChangeAnyonePasswordRequest */ -export interface ApiConsoleHaloRunV1alpha1UserApiChangePasswordRequest { +export interface ApiConsoleHaloRunV1alpha1UserApiChangeAnyonePasswordRequest { /** * Name of user. If the name is equal to \'-\', it will change the password of current user. * @type {string} - * @memberof ApiConsoleHaloRunV1alpha1UserApiChangePassword + * @memberof ApiConsoleHaloRunV1alpha1UserApiChangeAnyonePassword */ readonly name: string /** * * @type {ChangePasswordRequest} - * @memberof ApiConsoleHaloRunV1alpha1UserApiChangePassword + * @memberof ApiConsoleHaloRunV1alpha1UserApiChangeAnyonePassword */ readonly changePasswordRequest: ChangePasswordRequest } +/** + * Request parameters for changeOwnPassword operation in ApiConsoleHaloRunV1alpha1UserApi. + * @export + * @interface ApiConsoleHaloRunV1alpha1UserApiChangeOwnPasswordRequest + */ +export interface ApiConsoleHaloRunV1alpha1UserApiChangeOwnPasswordRequest { + /** + * + * @type {ChangeOwnPasswordRequest} + * @memberof ApiConsoleHaloRunV1alpha1UserApiChangeOwnPassword + */ + readonly changeOwnPasswordRequest: ChangeOwnPasswordRequest +} + /** * Request parameters for createUser operation in ApiConsoleHaloRunV1alpha1UserApi. * @export @@ -1102,14 +1182,25 @@ export interface ApiConsoleHaloRunV1alpha1UserApiVerifyEmailRequest { */ export class ApiConsoleHaloRunV1alpha1UserApi extends BaseAPI { /** - * Change password of user. - * @param {ApiConsoleHaloRunV1alpha1UserApiChangePasswordRequest} requestParameters Request parameters. + * Change anyone password of user for admin. + * @param {ApiConsoleHaloRunV1alpha1UserApiChangeAnyonePasswordRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ApiConsoleHaloRunV1alpha1UserApi + */ + public changeAnyonePassword(requestParameters: ApiConsoleHaloRunV1alpha1UserApiChangeAnyonePasswordRequest, options?: RawAxiosRequestConfig) { + return ApiConsoleHaloRunV1alpha1UserApiFp(this.configuration).changeAnyonePassword(requestParameters.name, requestParameters.changePasswordRequest, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * Change own password of user. + * @param {ApiConsoleHaloRunV1alpha1UserApiChangeOwnPasswordRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof ApiConsoleHaloRunV1alpha1UserApi */ - public changePassword(requestParameters: ApiConsoleHaloRunV1alpha1UserApiChangePasswordRequest, options?: RawAxiosRequestConfig) { - return ApiConsoleHaloRunV1alpha1UserApiFp(this.configuration).changePassword(requestParameters.name, requestParameters.changePasswordRequest, options).then((request) => request(this.axios, this.basePath)); + public changeOwnPassword(requestParameters: ApiConsoleHaloRunV1alpha1UserApiChangeOwnPasswordRequest, options?: RawAxiosRequestConfig) { + return ApiConsoleHaloRunV1alpha1UserApiFp(this.configuration).changeOwnPassword(requestParameters.changeOwnPasswordRequest, options).then((request) => request(this.axios, this.basePath)); } /** diff --git a/ui/packages/api-client/src/models/change-own-password-request.ts b/ui/packages/api-client/src/models/change-own-password-request.ts new file mode 100644 index 0000000000..1e3ba906bd --- /dev/null +++ b/ui/packages/api-client/src/models/change-own-password-request.ts @@ -0,0 +1,36 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo Next API + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.0.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + + +/** + * + * @export + * @interface ChangeOwnPasswordRequest + */ +export interface ChangeOwnPasswordRequest { + /** + * Old password. + * @type {string} + * @memberof ChangeOwnPasswordRequest + */ + 'oldPassword': string; + /** + * New password. + * @type {string} + * @memberof ChangeOwnPasswordRequest + */ + 'password': string; +} + diff --git a/ui/packages/api-client/src/models/index.ts b/ui/packages/api-client/src/models/index.ts index d5c688d357..b0acf1a96b 100644 --- a/ui/packages/api-client/src/models/index.ts +++ b/ui/packages/api-client/src/models/index.ts @@ -19,6 +19,7 @@ export * from './category-spec'; export * from './category-status'; export * from './category-vo'; export * from './category-vo-list'; +export * from './change-own-password-request'; export * from './change-password-request'; export * from './comment'; export * from './comment-email-owner'; diff --git a/ui/src/locales/en.yaml b/ui/src/locales/en.yaml index f6f0e554fc..c68420eac9 100644 --- a/ui/src/locales/en.yaml +++ b/ui/src/locales/en.yaml @@ -919,7 +919,10 @@ core: fields: username: label: Username - validation: Can only contain numbers, lowercase letters, periods (.), and hyphens (-), and cannot start or end with a period (.) or hyphen (-). + validation: >- + Can only contain numbers, lowercase letters, periods (.), and + hyphens (-), and cannot start or end with a period (.) or hyphen + (-). display_name: label: Display name email: @@ -1117,7 +1120,10 @@ core: fields: username: label: Username - validation: Can only contain numbers, lowercase letters, periods (.), and hyphens (-), and cannot start or end with a period (.) or hyphen (-). + validation: >- + Can only contain numbers, lowercase letters, periods (.), and + hyphens (-), and cannot start or end with a period (.) or hyphen + (-). display_name: label: Display name email: @@ -1135,6 +1141,8 @@ core: label: New password confirm_password: label: Confirm password + old_password: + label: Old password email_verify_modal: fields: code: diff --git a/ui/src/locales/zh-CN.yaml b/ui/src/locales/zh-CN.yaml index 7e48d4c825..730e3853ad 100644 --- a/ui/src/locales/zh-CN.yaml +++ b/ui/src/locales/zh-CN.yaml @@ -1083,6 +1083,8 @@ core: label: 新密码 confirm_password: label: 确认密码 + old_password: + label: 旧密码 email_verify_modal: titles: modify: 修改电子邮箱 diff --git a/ui/src/locales/zh-TW.yaml b/ui/src/locales/zh-TW.yaml index d99e5ea579..ae7bd893d5 100644 --- a/ui/src/locales/zh-TW.yaml +++ b/ui/src/locales/zh-TW.yaml @@ -1071,6 +1071,8 @@ core: label: 新密碼 confirm_password: label: 確認密碼 + old_password: + label: 舊密碼 email_verify_modal: fields: code: diff --git a/ui/uc-src/modules/profile/components/PasswordChangeModal.vue b/ui/uc-src/modules/profile/components/PasswordChangeModal.vue index c60b262f2f..d99c80b264 100644 --- a/ui/uc-src/modules/profile/components/PasswordChangeModal.vue +++ b/ui/uc-src/modules/profile/components/PasswordChangeModal.vue @@ -25,11 +25,13 @@ const emit = defineEmits<{ }>(); interface PasswordChangeFormState { + oldPassword: string; password: string; password_confirm?: string; } const initialFormState: PasswordChangeFormState = { + oldPassword: "", password: "", password_confirm: "", }; @@ -64,12 +66,11 @@ const handleChangePassword = async () => { try { saving.value = true; - const changePasswordRequest = cloneDeep(formState.value); - delete changePasswordRequest.password_confirm; + const changeOwnPasswordRequest = cloneDeep(formState.value); + delete changeOwnPasswordRequest.password_confirm; - await apiClient.user.changePassword({ - name: "-", - changePasswordRequest, + await apiClient.user.changeOwnPassword({ + changeOwnPasswordRequest, }); onVisibleChange(false); @@ -99,6 +100,14 @@ const handleChangePassword = async () => { > +