change password is modified
This commit is contained in:
parent
68e861a39b
commit
31153b52bf
|
@ -5,6 +5,9 @@
|
|||
<mat-card-content>
|
||||
<div fxFlex class="setting-tab">
|
||||
<ucap-account-change-password
|
||||
[loginId]="data.loginId"
|
||||
[phoneNumber]="data.phoneNumber"
|
||||
[encryptedLoginPw]="data.encryptedLoginPw"
|
||||
(changePassword)="onChangePassword($event)"
|
||||
></ucap-account-change-password>
|
||||
</div>
|
||||
|
|
|
@ -1,24 +1,18 @@
|
|||
import { Component, OnInit, Inject, OnDestroy } from '@angular/core';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
|
||||
import { KEY_LOGIN_RES_INFO } from '@app/types/login-res-info.type';
|
||||
import { KEY_VER_INFO } from '@app/types/ver-info.type';
|
||||
import { SessionStorageService } from '@ucap-webmessenger/web-storage';
|
||||
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
import { DialogService } from '@ucap-webmessenger/ui';
|
||||
import { VersionInfo2Response } from '@ucap-webmessenger/api-public';
|
||||
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
|
||||
import { AppAuthenticationService } from '@app/services/authentication.service';
|
||||
import { StringUtil, CharactorType } from '@ucap-webmessenger/core';
|
||||
|
||||
import * as ServiceStore from '@app/store/messenger/service';
|
||||
import CryptoJS from 'crypto-js';
|
||||
|
||||
export interface ChangePasswordDialogData {}
|
||||
export interface ChangePasswordDialogData {
|
||||
loginId: string;
|
||||
phoneNumber?: string;
|
||||
encryptedLoginPw?: string;
|
||||
}
|
||||
|
||||
export interface ChangePasswordDialogResult {
|
||||
choice: boolean;
|
||||
currentLoginPw?: string;
|
||||
newLoginPw?: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
|
@ -27,170 +21,25 @@ export interface ChangePasswordDialogResult {
|
|||
styleUrls: ['./change-password.dialog.component.scss']
|
||||
})
|
||||
export class ChangePasswordDialogComponent implements OnInit, OnDestroy {
|
||||
loginRes: LoginResponse;
|
||||
sessionVerinfo: VersionInfo2Response;
|
||||
isMe: boolean;
|
||||
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<
|
||||
ChangePasswordDialogData,
|
||||
ChangePasswordDialogResult
|
||||
>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: ChangePasswordDialogData,
|
||||
private dialogService: DialogService,
|
||||
private sessionStorageService: SessionStorageService,
|
||||
private appAuthenticationService: AppAuthenticationService,
|
||||
private store: Store<any>
|
||||
) {
|
||||
this.sessionVerinfo = this.sessionStorageService.get<VersionInfo2Response>(
|
||||
KEY_VER_INFO
|
||||
);
|
||||
this.loginRes = this.sessionStorageService.get<LoginResponse>(
|
||||
KEY_LOGIN_RES_INFO
|
||||
);
|
||||
}
|
||||
private dialogService: DialogService
|
||||
) {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
ngOnDestroy(): void {}
|
||||
|
||||
onChangePassword(info: {
|
||||
currentLoginPw: string;
|
||||
newLoginPw: string;
|
||||
newConfirmLoginPw: string;
|
||||
notValid: () => void;
|
||||
}): void {
|
||||
if (!info.currentLoginPw || '' === info.currentLoginPw.trim()) {
|
||||
// 현재 비밀번호를 입력해주세요
|
||||
info.notValid();
|
||||
return;
|
||||
}
|
||||
if (!this.appAuthenticationService.isSameForPassword(info.currentLoginPw)) {
|
||||
// "현재 비밀번호가 다릅니다"
|
||||
info.notValid();
|
||||
return;
|
||||
}
|
||||
if (!info.newLoginPw || '' === info.newLoginPw.trim()) {
|
||||
// 신규 비밀번호를 입력해주세요
|
||||
info.notValid();
|
||||
return;
|
||||
}
|
||||
if (-1 < info.newLoginPw.indexOf(this.loginRes.userId)) {
|
||||
// "사용자 ID를 비밀번호에 포함할 수 없습니다."
|
||||
info.notValid();
|
||||
return;
|
||||
}
|
||||
const phoneNumberOnly = !!this.loginRes.userInfo.hpNumber
|
||||
? this.loginRes.userInfo.hpNumber.trim().replace(new RegExp('-', 'g'), '')
|
||||
: '';
|
||||
|
||||
switch (phoneNumberOnly.length) {
|
||||
case 11:
|
||||
if (-1 < info.newLoginPw.indexOf(phoneNumberOnly.substr(3, 4))) {
|
||||
// "사용자 휴대폰번호를 비밀번호에 포함할 수 없습니다."
|
||||
info.notValid();
|
||||
return;
|
||||
}
|
||||
if (-1 < info.newLoginPw.indexOf(phoneNumberOnly.substr(7, 4))) {
|
||||
// "사용자 휴대폰번호를 비밀번호에 포함할 수 없습니다."
|
||||
info.notValid();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
if (-1 < info.newLoginPw.indexOf(phoneNumberOnly.substr(3, 3))) {
|
||||
// "사용자 휴대폰번호를 비밀번호에 포함할 수 없습니다."
|
||||
info.notValid();
|
||||
return;
|
||||
}
|
||||
if (-1 < info.newLoginPw.indexOf(phoneNumberOnly.substr(6, 4))) {
|
||||
// "사용자 휴대폰번호를 비밀번호에 포함할 수 없습니다."
|
||||
info.notValid();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!info.newConfirmLoginPw || '' === info.newConfirmLoginPw.trim()) {
|
||||
// "신규 비밀번호 확인을 입력해주세요"
|
||||
info.notValid();
|
||||
return;
|
||||
}
|
||||
if (info.newLoginPw !== info.newConfirmLoginPw.trim()) {
|
||||
// "신규 비밀번호와 신규 비밀번호 확인이 다릅니다"
|
||||
info.notValid();
|
||||
return;
|
||||
}
|
||||
if (info.currentLoginPw === info.newLoginPw.trim()) {
|
||||
// "현재 비밀번호와 새로운 비밀번호가 같습니다."
|
||||
info.notValid();
|
||||
return;
|
||||
}
|
||||
if (0 < StringUtil.includes(info.newLoginPw, CharactorType.Space)) {
|
||||
// "비밀번호에는 공백을 입력할 수 없습니다."
|
||||
info.notValid();
|
||||
return;
|
||||
}
|
||||
if (StringUtil.isRepeat(info.newLoginPw, 3)) {
|
||||
// "숫자나 문자를 3번이상 반복적으로 사용할 수 없습니다."
|
||||
info.notValid();
|
||||
return;
|
||||
}
|
||||
if (
|
||||
StringUtil.isIncrements(info.newLoginPw, 3) ||
|
||||
StringUtil.isDecrements(info.newLoginPw, 3)
|
||||
) {
|
||||
// "연속되는 숫자나 문자를 3번이상 사용할 수 없습니다."
|
||||
info.notValid();
|
||||
return;
|
||||
}
|
||||
|
||||
let combinationCount = 0;
|
||||
if (0 < StringUtil.includes(info.newLoginPw, CharactorType.Special)) {
|
||||
combinationCount++;
|
||||
}
|
||||
if (0 < StringUtil.includes(info.newLoginPw, CharactorType.Number)) {
|
||||
combinationCount++;
|
||||
}
|
||||
if (0 < StringUtil.includes(info.newLoginPw, CharactorType.Charactor)) {
|
||||
combinationCount++;
|
||||
}
|
||||
|
||||
let minPwLen = 0;
|
||||
if (2 < combinationCount) {
|
||||
minPwLen = 8;
|
||||
} else if (2 === combinationCount) {
|
||||
minPwLen = 10;
|
||||
} else if (2 > combinationCount) {
|
||||
// "2종류 이상 조합을 해야 합니다."
|
||||
info.notValid();
|
||||
return;
|
||||
}
|
||||
|
||||
if (info.newLoginPw.length < minPwLen) {
|
||||
// "비밀번호는 %d가지가 조합된 경우 %d자를 넘어야 합니다."
|
||||
info.notValid();
|
||||
return;
|
||||
}
|
||||
|
||||
this.store.dispatch(
|
||||
ServiceStore.userPasswordSet({
|
||||
req: {
|
||||
loginId: this.loginRes.userId,
|
||||
companyCode: this.loginRes.companyCode,
|
||||
oldLoginPw: CryptoJS.enc.Hex.stringify(
|
||||
CryptoJS.SHA256(info.currentLoginPw)
|
||||
),
|
||||
newLoginPw: CryptoJS.enc.Hex.stringify(
|
||||
CryptoJS.SHA256(info.newLoginPw)
|
||||
)
|
||||
}
|
||||
})
|
||||
);
|
||||
this.dialogRef.close({ choice: true });
|
||||
onChangePassword(info: { currentLoginPw: string; newLoginPw: string }): void {
|
||||
this.dialogRef.close({
|
||||
choice: true,
|
||||
currentLoginPw: info.currentLoginPw,
|
||||
newLoginPw: info.newLoginPw
|
||||
});
|
||||
}
|
||||
|
||||
onClickChoice(choice: boolean): void {
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
|
||||
import CryptoJS from 'crypto-js';
|
||||
|
||||
import {
|
||||
SessionStorageService,
|
||||
LocalStorageService
|
||||
|
@ -10,6 +8,7 @@ import { LocaleCode } from '@ucap-webmessenger/core';
|
|||
import { LoginInfo, KEY_LOGIN_INFO } from '../types';
|
||||
import { KEY_VER_INFO } from '@app/types/ver-info.type';
|
||||
import { KEY_LOGIN_RES_INFO } from '@app/types/login-res-info.type';
|
||||
import { PasswordUtil } from '@ucap-webmessenger/pi';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
@ -33,7 +32,7 @@ export class AppAuthenticationService {
|
|||
this.sessionStorageService.set<LoginInfo>(KEY_LOGIN_INFO, {
|
||||
...loginInfo,
|
||||
initPw: loginInfo.loginId === loginInfo.loginPw,
|
||||
loginPw: CryptoJS.enc.Hex.stringify(CryptoJS.SHA256(loginInfo.loginPw))
|
||||
loginPw: PasswordUtil.encrypt(loginInfo.loginPw)
|
||||
});
|
||||
|
||||
if (rememberMe) {
|
||||
|
@ -51,11 +50,4 @@ export class AppAuthenticationService {
|
|||
this.sessionStorageService.remove(KEY_VER_INFO);
|
||||
this.sessionStorageService.remove(KEY_LOGIN_INFO);
|
||||
}
|
||||
|
||||
isSameForPassword(pw: string): boolean {
|
||||
const loginInfo = this.sessionStorageService.get<LoginInfo>(KEY_LOGIN_INFO);
|
||||
return (
|
||||
loginInfo.loginPw === CryptoJS.enc.Hex.stringify(CryptoJS.SHA256(pw))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,3 +96,20 @@ export const privacyAgreeFailure = createAction(
|
|||
export const privacyDisagree = createAction(
|
||||
'[Account::Authentication] Privacy Disagree'
|
||||
);
|
||||
|
||||
export const userPasswordSet = createAction(
|
||||
'[Account::Authentication] User Password Set',
|
||||
props<{ req: UserPasswordSetRequest }>()
|
||||
);
|
||||
|
||||
export const userPasswordSetSuccess = createAction(
|
||||
'[Account::Authentication] User Password Set Success',
|
||||
props<{
|
||||
res: UserPasswordSetResponse;
|
||||
}>()
|
||||
);
|
||||
|
||||
export const userPasswordSetFailure = createAction(
|
||||
'[Account::Authentication] User Password Set Failure',
|
||||
props<{ error: any }>()
|
||||
);
|
||||
|
|
|
@ -34,7 +34,10 @@ import {
|
|||
privacyAgreeSuccess,
|
||||
increaseLoginFailCount,
|
||||
initialLoginFailCount,
|
||||
logoutInitialize
|
||||
logoutInitialize,
|
||||
userPasswordSet,
|
||||
userPasswordSetSuccess,
|
||||
userPasswordSetFailure
|
||||
} from './actions';
|
||||
import {
|
||||
LoginInfo,
|
||||
|
@ -60,6 +63,10 @@ import {
|
|||
ChangePasswordDialogData,
|
||||
ChangePasswordDialogResult
|
||||
} from '@app/layouts/messenger/dialogs/account/change-password.dialog.component';
|
||||
import {
|
||||
ServiceProtocolService,
|
||||
UserPasswordSetResponse
|
||||
} from '@ucap-webmessenger/protocol-service';
|
||||
|
||||
@Injectable()
|
||||
export class Effects {
|
||||
|
@ -273,10 +280,24 @@ export class Effects {
|
|||
width: '500px',
|
||||
height: '500px',
|
||||
disableClose: false,
|
||||
data: {}
|
||||
data: {
|
||||
loginId: loginInfo.loginId,
|
||||
encryptedLoginPw: loginInfo.loginPw,
|
||||
phoneNumber: loginRes.userInfo.hpNumber
|
||||
}
|
||||
});
|
||||
|
||||
if (!!result && result.choice) {
|
||||
this.store.dispatch(
|
||||
userPasswordSet({
|
||||
req: {
|
||||
companyCode: loginInfo.companyCode,
|
||||
loginId: loginInfo.loginId,
|
||||
oldLoginPw: result.currentLoginPw,
|
||||
newLoginPw: result.newLoginPw
|
||||
}
|
||||
})
|
||||
);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
@ -324,6 +345,23 @@ export class Effects {
|
|||
)
|
||||
);
|
||||
|
||||
userPasswordSet$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(userPasswordSet),
|
||||
map(action => action.req),
|
||||
exhaustMap(req =>
|
||||
this.serviceProtocolService.userPasswordSet(req).pipe(
|
||||
map((res: UserPasswordSetResponse) => {
|
||||
return userPasswordSetSuccess({
|
||||
res
|
||||
});
|
||||
}),
|
||||
catchError(error => of(userPasswordSetFailure({ error })))
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
constructor(
|
||||
private actions$: Actions,
|
||||
private ngZone: NgZone,
|
||||
|
@ -334,7 +372,7 @@ export class Effects {
|
|||
private appAuthenticationService: AppAuthenticationService,
|
||||
private protocolService: ProtocolService,
|
||||
private authenticationProtocolService: AuthenticationProtocolService,
|
||||
|
||||
private serviceProtocolService: ServiceProtocolService,
|
||||
private dialogService: DialogService,
|
||||
@Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
|
||||
private logger: NGXLogger
|
||||
|
|
|
@ -6,7 +6,6 @@ import * as EventStore from './event';
|
|||
import * as OptionStore from './option';
|
||||
import * as QueryStore from './query';
|
||||
import * as RoomStore from './room';
|
||||
import * as ServiceStore from './service';
|
||||
import * as StatusStore from './status';
|
||||
import * as SyncStore from './sync';
|
||||
import * as SettingsStore from './settings';
|
||||
|
@ -17,7 +16,6 @@ export interface State {
|
|||
option: OptionStore.State;
|
||||
query: QueryStore.State;
|
||||
room: RoomStore.State;
|
||||
service: ServiceStore.State;
|
||||
status: StatusStore.State;
|
||||
sync: SyncStore.State;
|
||||
settings: SettingsStore.State;
|
||||
|
@ -29,7 +27,6 @@ export const effects: Type<any>[] = [
|
|||
OptionStore.Effects,
|
||||
QueryStore.Effects,
|
||||
RoomStore.Effects,
|
||||
ServiceStore.Effects,
|
||||
StatusStore.Effects,
|
||||
SyncStore.Effects,
|
||||
SettingsStore.Effects
|
||||
|
@ -42,7 +39,6 @@ export function reducers(state: State | undefined, action: Action) {
|
|||
option: OptionStore.reducer,
|
||||
query: QueryStore.reducer,
|
||||
room: RoomStore.reducer,
|
||||
service: ServiceStore.reducer,
|
||||
status: StatusStore.reducer,
|
||||
sync: SyncStore.reducer,
|
||||
settings: SettingsStore.reducer
|
||||
|
@ -66,9 +62,6 @@ export function selectors<S>(selector: Selector<any, State>) {
|
|||
QuerySelector: QueryStore.selectors(
|
||||
createSelector(selector, (state: State) => state.query)
|
||||
),
|
||||
ServiceSelector: ServiceStore.selectors(
|
||||
createSelector(selector, (state: State) => state.service)
|
||||
),
|
||||
StatusSelector: StatusStore.selectors(
|
||||
createSelector(selector, (state: State) => state.status)
|
||||
),
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
import { createAction, props } from '@ngrx/store';
|
||||
|
||||
import {
|
||||
UserPasswordSetRequest,
|
||||
UserPasswordSetResponse
|
||||
} from '@ucap-webmessenger/protocol-service';
|
||||
|
||||
export const userPasswordSet = createAction(
|
||||
'[Account::Authentication] User Password Set',
|
||||
props<{ req: UserPasswordSetRequest }>()
|
||||
);
|
||||
|
||||
export const userPasswordSetSuccess = createAction(
|
||||
'[Account::Authentication] User Password Set Success',
|
||||
props<{
|
||||
res: UserPasswordSetResponse;
|
||||
}>()
|
||||
);
|
||||
|
||||
export const userPasswordSetFailure = createAction(
|
||||
'[Account::Authentication] User Password Set Failure',
|
||||
props<{ error: any }>()
|
||||
);
|
|
@ -1,47 +0,0 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { Actions, ofType, createEffect } from '@ngrx/effects';
|
||||
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { catchError, exhaustMap, map } from 'rxjs/operators';
|
||||
|
||||
import { of } from 'rxjs';
|
||||
|
||||
import {
|
||||
userPasswordSet,
|
||||
userPasswordSetSuccess,
|
||||
userPasswordSetFailure
|
||||
} from './actions';
|
||||
import {
|
||||
ServiceProtocolService,
|
||||
UserPasswordSetResponse
|
||||
} from '@ucap-webmessenger/protocol-service';
|
||||
|
||||
@Injectable()
|
||||
export class Effects {
|
||||
userPasswordSet$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(userPasswordSet),
|
||||
map(action => action.req),
|
||||
exhaustMap(req =>
|
||||
this.serviceProtocolService.userPasswordSet(req).pipe(
|
||||
map((res: UserPasswordSetResponse) => {
|
||||
return userPasswordSetSuccess({
|
||||
res
|
||||
});
|
||||
}),
|
||||
catchError(error => of(userPasswordSetFailure({ error })))
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
constructor(
|
||||
private actions$: Actions,
|
||||
private serviceProtocolService: ServiceProtocolService,
|
||||
private store: Store<any>,
|
||||
private logger: NGXLogger
|
||||
) {}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
export * from './actions';
|
||||
export * from './effects';
|
||||
export * from './reducers';
|
||||
export * from './state';
|
|
@ -1,4 +0,0 @@
|
|||
import { createReducer, on } from '@ngrx/store';
|
||||
import { initialState } from './state';
|
||||
|
||||
export const reducer = createReducer(initialState);
|
|
@ -1,9 +0,0 @@
|
|||
import { Selector, createSelector } from '@ngrx/store';
|
||||
|
||||
export interface State {}
|
||||
|
||||
export const initialState: State = {};
|
||||
|
||||
export function selectors<S>(selector: Selector<any, State>) {
|
||||
return {};
|
||||
}
|
137
projects/ucap-webmessenger-pi/src/lib/utils/password.util.ts
Normal file
137
projects/ucap-webmessenger-pi/src/lib/utils/password.util.ts
Normal file
|
@ -0,0 +1,137 @@
|
|||
import CryptoJS from 'crypto-js';
|
||||
import { StringUtil, CharactorType } from '@ucap-webmessenger/core';
|
||||
|
||||
export interface PasswordValidationOption {
|
||||
userId?: string;
|
||||
phoneNumber?: string;
|
||||
}
|
||||
|
||||
export enum PasswordValidationResult {
|
||||
Valid = 'Valid',
|
||||
Empty = 'Empty',
|
||||
IncludeUserId = 'IncludeUserId',
|
||||
IncludePhoneNumber = 'IncludePhoneNumber',
|
||||
IncludeSpace = 'IncludeSpace',
|
||||
IncludeRepeated = 'IncludeRepeated',
|
||||
IncludeIncrements = 'IncludeIncrements',
|
||||
IncludeDecrements = 'IncludeDecrements',
|
||||
LackOfCombination = 'LackOfCombination',
|
||||
TooShortCombinationLength = 'TooShortCombinationLength'
|
||||
}
|
||||
|
||||
export class PasswordUtil {
|
||||
static encrypt(password: string): string {
|
||||
return CryptoJS.enc.Hex.stringify(CryptoJS.SHA256(password));
|
||||
}
|
||||
|
||||
static validate(
|
||||
password: string,
|
||||
option?: PasswordValidationOption
|
||||
): { code: PasswordValidationResult; extra?: any } {
|
||||
if (!password || '' === password.trim()) {
|
||||
return {
|
||||
code: PasswordValidationResult.Empty
|
||||
};
|
||||
}
|
||||
|
||||
if (!!option && !!option.userId) {
|
||||
if (-1 < password.indexOf(option.userId)) {
|
||||
return {
|
||||
code: PasswordValidationResult.IncludeUserId
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (!!option && !!option.phoneNumber) {
|
||||
const phoneNumberOnly = option.phoneNumber
|
||||
.trim()
|
||||
.replace(new RegExp('-', 'g'), '');
|
||||
|
||||
switch (phoneNumberOnly.length) {
|
||||
case 11:
|
||||
if (-1 < password.indexOf(phoneNumberOnly.substr(3, 4))) {
|
||||
return {
|
||||
code: PasswordValidationResult.IncludePhoneNumber
|
||||
};
|
||||
}
|
||||
if (-1 < password.indexOf(phoneNumberOnly.substr(7, 4))) {
|
||||
return {
|
||||
code: PasswordValidationResult.IncludePhoneNumber
|
||||
};
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
if (-1 < password.indexOf(phoneNumberOnly.substr(3, 3))) {
|
||||
return {
|
||||
code: PasswordValidationResult.IncludePhoneNumber
|
||||
};
|
||||
}
|
||||
if (-1 < password.indexOf(phoneNumberOnly.substr(6, 4))) {
|
||||
return {
|
||||
code: PasswordValidationResult.IncludePhoneNumber
|
||||
};
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 < StringUtil.includes(password, CharactorType.Space)) {
|
||||
return {
|
||||
code: PasswordValidationResult.IncludeSpace
|
||||
};
|
||||
}
|
||||
if (StringUtil.isRepeat(password, 3)) {
|
||||
return {
|
||||
code: PasswordValidationResult.IncludeRepeated
|
||||
};
|
||||
}
|
||||
if (StringUtil.isIncrements(password, 3)) {
|
||||
return {
|
||||
code: PasswordValidationResult.IncludeIncrements
|
||||
};
|
||||
}
|
||||
if (StringUtil.isDecrements(password, 3)) {
|
||||
return {
|
||||
code: PasswordValidationResult.IncludeDecrements
|
||||
};
|
||||
}
|
||||
|
||||
let combinationCount = 0;
|
||||
if (0 < StringUtil.includes(password, CharactorType.Special)) {
|
||||
combinationCount++;
|
||||
}
|
||||
if (0 < StringUtil.includes(password, CharactorType.Number)) {
|
||||
combinationCount++;
|
||||
}
|
||||
if (0 < StringUtil.includes(password, CharactorType.Charactor)) {
|
||||
combinationCount++;
|
||||
}
|
||||
|
||||
let minPwLen = 0;
|
||||
if (2 < combinationCount) {
|
||||
minPwLen = 8;
|
||||
} else if (2 === combinationCount) {
|
||||
minPwLen = 10;
|
||||
} else if (2 > combinationCount) {
|
||||
return {
|
||||
code: PasswordValidationResult.LackOfCombination
|
||||
};
|
||||
}
|
||||
|
||||
if (password.length < minPwLen) {
|
||||
return {
|
||||
code: PasswordValidationResult.TooShortCombinationLength,
|
||||
extra: {
|
||||
combinationCount,
|
||||
minPwLen
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
code: PasswordValidationResult.Valid
|
||||
};
|
||||
}
|
||||
}
|
|
@ -12,6 +12,8 @@ export * from './lib/types/response-status.type';
|
|||
|
||||
export * from './lib/services/pi.service';
|
||||
|
||||
export * from './lib/utils/password.util';
|
||||
|
||||
export * from './lib/ucap-pi.module';
|
||||
|
||||
export * from './lib/config/urls';
|
||||
|
|
|
@ -5,43 +5,137 @@
|
|||
<input
|
||||
matInput
|
||||
type="password"
|
||||
formControlName="currentLoginPw"
|
||||
#currentLoginPw
|
||||
[formControl]="currentLoginPwFormControl"
|
||||
/>
|
||||
<mat-error>
|
||||
현재 패스워드를 입력해 주세요
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>신규 패스워드</mat-label>
|
||||
<input
|
||||
matInput
|
||||
type="password"
|
||||
formControlName="newLoginPw"
|
||||
#newLoginPw
|
||||
/>
|
||||
<mat-error>
|
||||
신규 패스워드를 입력해 주세요
|
||||
</mat-error>
|
||||
<input matInput type="password" [formControl]="newLoginPwFormControl" />
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>신규 패스워드 확인</mat-label>
|
||||
<input
|
||||
matInput
|
||||
type="password"
|
||||
formControlName="newConfirmLoginPw"
|
||||
#newConfirmLoginPw
|
||||
[formControl]="newConfirmLoginPwFormControl"
|
||||
/>
|
||||
<mat-error>
|
||||
신규 패스워드 확인을 입력해 주세요
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<div>
|
||||
<mat-error
|
||||
*ngIf="
|
||||
currentLoginPwFormControl.dirty &&
|
||||
currentLoginPwFormControl.hasError('required')
|
||||
"
|
||||
>
|
||||
현재 비밀번호를 입력해 주세요
|
||||
</mat-error>
|
||||
<mat-error
|
||||
*ngIf="
|
||||
currentLoginPwFormControl.dirty &&
|
||||
currentLoginPwFormControl.hasError('ucapPasswordSame')
|
||||
"
|
||||
>
|
||||
현재 비밀번호와 일치하지 않습니다
|
||||
</mat-error>
|
||||
|
||||
<mat-error
|
||||
*ngIf="
|
||||
newLoginPwFormControl.dirty &&
|
||||
newLoginPwFormControl.hasError('required')
|
||||
"
|
||||
>
|
||||
신규 비밀번호를 입력해 주세요
|
||||
</mat-error>
|
||||
<mat-error
|
||||
*ngIf="
|
||||
newLoginPwFormControl.dirty &&
|
||||
newLoginPwFormControl.hasError('ucapNotSameWith')
|
||||
"
|
||||
>
|
||||
현재 비밀번호와 동일합니다
|
||||
</mat-error>
|
||||
<mat-error
|
||||
*ngIf="
|
||||
newLoginPwFormControl.dirty &&
|
||||
newLoginPwFormControl.hasError('ucapPassword')
|
||||
"
|
||||
>
|
||||
<ng-container
|
||||
[ngSwitch]="
|
||||
newLoginPwFormControl.getError('ucapPassword').result.code
|
||||
"
|
||||
>
|
||||
<ng-container *ngSwitchCase="PasswordValidationResult.IncludeSpace">
|
||||
비밀번호에는 공백을 입력할 수 없습니다
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="PasswordValidationResult.IncludeUserId">
|
||||
사용자 ID를 비밀번호에 포함할 수 없습니다
|
||||
</ng-container>
|
||||
<ng-container
|
||||
*ngSwitchCase="PasswordValidationResult.IncludePhoneNumber"
|
||||
>
|
||||
사용자 휴대폰번호를 비밀번호에 포함할 수 없습니다
|
||||
</ng-container>
|
||||
<ng-container
|
||||
*ngSwitchCase="PasswordValidationResult.IncludeRepeated"
|
||||
>
|
||||
숫자나 문자를 3번이상 반복적으로 사용할 수 없습니다
|
||||
</ng-container>
|
||||
<ng-container
|
||||
*ngSwitchCase="PasswordValidationResult.IncludeIncrements"
|
||||
>
|
||||
연속되는 숫자나 문자를 3번이상 사용할 수 없습니다
|
||||
</ng-container>
|
||||
<ng-container
|
||||
*ngSwitchCase="PasswordValidationResult.IncludeDecrements"
|
||||
>
|
||||
연속되는 숫자나 문자를 3번이상 사용할 수 없습니다
|
||||
</ng-container>
|
||||
<ng-container
|
||||
*ngSwitchCase="PasswordValidationResult.LackOfCombination"
|
||||
>
|
||||
2종류 이상 조합을 해야 합니다
|
||||
</ng-container>
|
||||
<ng-container
|
||||
*ngSwitchCase="PasswordValidationResult.TooShortCombinationLength"
|
||||
>
|
||||
비밀번호에는 공백을 입력할 수 없습니다
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="PasswordValidationResult.IncludeSpace">
|
||||
비밀번호는{{
|
||||
newLoginPwFormControl.getError('ucapPassword').result.extra
|
||||
.combinationCount
|
||||
}}가지가 조합된 경우{{
|
||||
newLoginPwFormControl.getError('ucapPassword').result.extra
|
||||
.minPwLen
|
||||
}}자를 넘어야 합니다
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</mat-error>
|
||||
<mat-error
|
||||
*ngIf="
|
||||
newConfirmLoginPwFormControl.dirty &&
|
||||
newConfirmLoginPwFormControl.hasError('required')
|
||||
"
|
||||
>
|
||||
신규 비밀번호 확인을 입력해 주세요
|
||||
</mat-error>
|
||||
<mat-error
|
||||
*ngIf="
|
||||
newConfirmLoginPwFormControl.dirty &&
|
||||
newConfirmLoginPwFormControl.hasError('ucapSameWith')
|
||||
"
|
||||
>
|
||||
신규 비밀번호와 신규 비밀번호 확인이 다릅니다
|
||||
</mat-error>
|
||||
</div>
|
||||
|
||||
<button
|
||||
mat-raised-button
|
||||
class="submit-button bg-accent-dark"
|
||||
aria-label="패스워드 변경"
|
||||
[disabled]="changePasswordForm.invalid || !changePasswordBtnEnable"
|
||||
[disabled]="changePasswordForm.invalid"
|
||||
(click)="onClickChangePassword()"
|
||||
>
|
||||
패스워드 변경
|
||||
|
|
|
@ -8,10 +8,66 @@ import {
|
|||
ElementRef,
|
||||
ChangeDetectorRef
|
||||
} from '@angular/core';
|
||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||
import { Company } from '@ucap-webmessenger/api-external';
|
||||
import { LocalStorageService } from '@ucap-webmessenger/web-storage';
|
||||
import { LoginInfo, KEY_LOGIN_INFO } from '@app/types';
|
||||
import {
|
||||
FormControl,
|
||||
FormGroup,
|
||||
Validators,
|
||||
ValidatorFn,
|
||||
AbstractControl,
|
||||
ValidationErrors,
|
||||
FormBuilder
|
||||
} from '@angular/forms';
|
||||
import {
|
||||
PasswordUtil,
|
||||
PasswordValidationOption,
|
||||
PasswordValidationResult
|
||||
} from '@ucap-webmessenger/pi';
|
||||
|
||||
export function ucapPassword(option: PasswordValidationOption): ValidatorFn {
|
||||
return (control: AbstractControl): ValidationErrors | null => {
|
||||
const result = PasswordUtil.validate(control.value, option);
|
||||
return PasswordValidationResult.Valid !== result.code
|
||||
? { ucapPassword: { result } }
|
||||
: null;
|
||||
};
|
||||
}
|
||||
|
||||
export function ucapPasswordSame(value: string): ValidatorFn {
|
||||
return (control: AbstractControl): ValidationErrors | null => {
|
||||
return !!value && value !== PasswordUtil.encrypt(control.value)
|
||||
? { ucapPasswordSame: true }
|
||||
: null;
|
||||
};
|
||||
}
|
||||
|
||||
export function ucapNotSameWith(targetControl: AbstractControl): ValidatorFn {
|
||||
return (control: AbstractControl): ValidationErrors | null => {
|
||||
return !!targetControl &&
|
||||
(targetControl.value as string) === (control.value as string)
|
||||
? { ucapNotSameWith: true }
|
||||
: null;
|
||||
};
|
||||
}
|
||||
|
||||
export function ucapSameWith(targetControl: AbstractControl): ValidatorFn {
|
||||
return (control: AbstractControl): ValidationErrors | null => {
|
||||
return !!targetControl && targetControl.value !== control.value
|
||||
? { ucapSameWith: true }
|
||||
: null;
|
||||
};
|
||||
}
|
||||
|
||||
export function ucapNotSame(value: string | number): ValidatorFn {
|
||||
return (control: AbstractControl): ValidationErrors | null => {
|
||||
return !!value && value === control.value ? { ucapNotSame: true } : null;
|
||||
};
|
||||
}
|
||||
|
||||
export function ucapSame(value: string | number): ValidatorFn {
|
||||
return (control: AbstractControl): ValidationErrors | null => {
|
||||
return !!value && value !== control.value ? { ucapSame: true } : null;
|
||||
};
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'ucap-account-change-password',
|
||||
|
@ -20,48 +76,79 @@ import { LoginInfo, KEY_LOGIN_INFO } from '@app/types';
|
|||
})
|
||||
export class ChangePasswordComponent implements OnInit {
|
||||
@Input()
|
||||
changePasswordBtnEnable: boolean;
|
||||
loginId: string;
|
||||
|
||||
@Input()
|
||||
phoneNumber: string;
|
||||
|
||||
@Input()
|
||||
encryptedLoginPw: string;
|
||||
|
||||
@Output()
|
||||
changePassword = new EventEmitter<{
|
||||
currentLoginPw: string;
|
||||
newLoginPw: string;
|
||||
newConfirmLoginPw: string;
|
||||
notValid: () => void;
|
||||
}>();
|
||||
|
||||
@ViewChild('currentLoginPw', { static: true })
|
||||
currentLoginPwElementRef: ElementRef;
|
||||
@ViewChild('newLoginPw', { static: true })
|
||||
newLoginPwElementRef: ElementRef;
|
||||
|
||||
changePasswordForm: FormGroup;
|
||||
currentLoginPwFormControl = new FormControl('');
|
||||
newLoginPwFormControl = new FormControl('');
|
||||
newConfirmLoginPwFormControl = new FormControl('');
|
||||
|
||||
PasswordValidationResult = PasswordValidationResult;
|
||||
|
||||
constructor(
|
||||
private formBuilder: FormBuilder,
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
private localStorageService: LocalStorageService
|
||||
private changeDetectorRef: ChangeDetectorRef
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
const loginInfo: LoginInfo = this.localStorageService.get<LoginInfo>(
|
||||
KEY_LOGIN_INFO
|
||||
const currentLoginPwValidators: ValidatorFn[] = [Validators.required];
|
||||
if (!!this.encryptedLoginPw) {
|
||||
currentLoginPwValidators.push(ucapPasswordSame(this.encryptedLoginPw));
|
||||
}
|
||||
this.currentLoginPwFormControl.setValidators(currentLoginPwValidators);
|
||||
|
||||
let validateOption: PasswordValidationOption = {};
|
||||
if (!!this.loginId) {
|
||||
validateOption = {
|
||||
...validateOption,
|
||||
userId: this.loginId
|
||||
};
|
||||
}
|
||||
if (!!this.phoneNumber) {
|
||||
validateOption = {
|
||||
...validateOption,
|
||||
phoneNumber: this.phoneNumber
|
||||
};
|
||||
}
|
||||
|
||||
const newLoginPwValidators: ValidatorFn[] = [
|
||||
Validators.required,
|
||||
ucapNotSameWith(this.currentLoginPwFormControl),
|
||||
ucapPassword(validateOption)
|
||||
];
|
||||
this.newLoginPwFormControl.setValidators(newLoginPwValidators);
|
||||
|
||||
const newConfirmLoginPwValidators: ValidatorFn[] = [
|
||||
Validators.required,
|
||||
ucapSameWith(this.newLoginPwFormControl)
|
||||
];
|
||||
this.newConfirmLoginPwFormControl.setValidators(
|
||||
newConfirmLoginPwValidators
|
||||
);
|
||||
|
||||
this.changePasswordForm = this.formBuilder.group({
|
||||
currentLoginPw: ['', Validators.required],
|
||||
newLoginPw: ['', Validators.required],
|
||||
newConfirmLoginPw: ['', Validators.required]
|
||||
currentLoginPwFormControl: this.currentLoginPwFormControl,
|
||||
newLoginPwFormControl: this.newLoginPwFormControl,
|
||||
newConfirmLoginPwFormControl: this.newConfirmLoginPwFormControl
|
||||
});
|
||||
}
|
||||
|
||||
onClickChangePassword() {
|
||||
this.changePassword.emit({
|
||||
currentLoginPw: this.changePasswordForm.get('currentLoginPw').value,
|
||||
newLoginPw: this.changePasswordForm.get('newLoginPw').value,
|
||||
newConfirmLoginPw: this.changePasswordForm.get('newConfirmLoginPw').value,
|
||||
notValid: () => {
|
||||
this.currentLoginPwElementRef.nativeElement.focus();
|
||||
}
|
||||
currentLoginPw: this.currentLoginPwFormControl.value,
|
||||
newLoginPw: this.newLoginPwFormControl.value
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user