This commit is contained in:
geek 2018-04-19 21:35:11 +09:00
parent 3eafb4dbc5
commit bd97afccc5
32 changed files with 297 additions and 238 deletions

View File

@ -20,7 +20,7 @@
</a> </a>
</li> </li>
<li role="menuitem"> <li role="menuitem">
<a href="#" class="ripplelink" [attr.tabindex]="!active ? '-1' : null"> <a [routerLink]="['/account/settings']" class="ripplelink" [attr.tabindex]="!active ? '-1' : null">
<i class="material-icons">settings_application</i> <i class="material-icons">settings_application</i>
<span>Settings</span> <span>Settings</span>
</a> </a>

View File

@ -2,7 +2,8 @@
<div class="ui-g"> <div class="ui-g">
<div class="ui-g-12"> <div class="ui-g-12">
<div class="card no-margin"> <div class="card no-margin">
<h1>Alert</h1> <h1>totp</h1>
<of-settings-totp></of-settings-totp>
</div> </div>
</div> </div>
</div> </div>

View File

@ -2,10 +2,12 @@ import { ProfileComponent } from './profile/profile.component';
import { SigninComponent } from './signin/signin.component'; import { SigninComponent } from './signin/signin.component';
import { SignupComponent } from './signup/signup.component'; import { SignupComponent } from './signup/signup.component';
import { ResetPasswordComponent } from './reset-password/reset-password.component'; import { ResetPasswordComponent } from './reset-password/reset-password.component';
import {SETTINGS_COMPONENTS} from './settings';
export const COMPONENTS = [ export const COMPONENTS = [
ProfileComponent, ProfileComponent,
SigninComponent, SigninComponent,
SignupComponent, SignupComponent,
ResetPasswordComponent, ResetPasswordComponent,
SETTINGS_COMPONENTS,
]; ];

View File

@ -0,0 +1,7 @@
import { TotpComponent } from './totp/totp.component';
import { ConfigSettingComponent } from './totp/config/config-setting.component';
export const SETTINGS_COMPONENTS = [
TotpComponent,
ConfigSettingComponent,
];

View File

@ -0,0 +1,79 @@
<div>
<div>
구글 인증기(OTP)는 암호 기능 중 하나입니다. 작동 원리는 SMS 인증 방식과 유사합니다.
연동 후 30초 마다 보안 코드가 생성되고, 보안 코드는 로그인, 인출, 보안 설정 변경등의 보안 인증을 하는 곳에 사용됩니다.
</div>
</div>
<div>
<div>
IOS 회원은 App Store에서 "Authenticator" 검색 후 다운로드 해주세요.
안드로이드 회원은 구글 플레이 스토어 또는 핸드폰 브라우저를 통해 "구글 인증기(OTP)" 검색 후 다운로드 해주세요.
</div>
</div>
<div class="ui-top-space-10" dir="auto">
<button type="button" class=" ui-button-width-fit"pButton type="button" label="App Store" icon="fa-check"></button>
<button type="button" class=" ui-button-width-fit"pButton type="button" label="Google Play" icon="fa-check"></button>
</div>
<div>
<p>Key & Backup Code</p>
<!--QR Code print & Key Print-->
</div>
<div class="ui-top-space-10" dir="rtl">
<button type="button" pButton icon="fa-check" (click)="totpSettingDisplay=false" label="Yes"></button>
<button type="button" class=" ui-button-width-fit" pButton icon="fa-close" (click)="onCancel()" label="No"></button>
</div>
<!--<p-panel>-->
<!--<p-header [style]="{'margin-bottom':'20px'}">-->
<!--<div>-->
<!--구글 인증기(OTP)는 암호 기능 중 하나입니다. 작동 원리는 SMS 인증 방식과 유사합니다.-->
<!--연동 후 30초 마다 보안 코드가 생성되고, 보안 코드는 로그인, 인출, 보안 설정 변경등의 보안 인증을 하는 곳에 사용됩니다.-->
<!--</div>-->
<!--</p-header>-->
<!--구글 인증기(OTP)는 암호 기능 중 하나입니다. 작동 원리는 SMS 인증 방식과 유사합니다.-->
<!--연동 후 30초 마다 보안 코드가 생성되고, 보안 코드는 로그인, 인출, 보안 설정 변경등의 보안 인증을 하는 곳에 사용됩니다.-->
<!--</p-panel>-->
<!--<p-panel>-->
<!--</p-panel>-->
<!--<div fxLayout="row" fxLayoutWrap fxLayoutAlign="center">-->
<!--<div fxLayout="row" fxLayoutWrap fxLayoutAlign="center">-->
<!--<mat-card class="example-card">-->
<!--<mat-card-header>-->
<!--<mat-card-title>QR Code</mat-card-title>-->
<!--&lt;!&ndash;<mat-card-subtitle>Select Target</mat-card-subtitle>&ndash;&gt;-->
<!--</mat-card-header>-->
<!--<mat-card-content>-->
<!--<div fxLayout="row" fxLayoutWrap fxLayoutAlign="left">-->
<!--<qrcode [qrdata]="'otpauth://totp/overFlow:geekdev@naver.com?secret=X6AWAK573M5372NM'" [size]="128" [level]="'M'"></qrcode>-->
<!--</div>-->
<!--</mat-card-content>-->
<!--</mat-card>-->
<!--</div>-->
<!--<div fxLayout="row" fxLayoutWrap fxLayoutAlign="center">-->
<!--<mat-card class="example-card">-->
<!--<mat-card-header>-->
<!--<mat-card-title>Secret Code</mat-card-title>-->
<!--<mat-card-subtitle>X6AWAK573M5372NM</mat-card-subtitle>-->
<!--</mat-card-header>-->
<!--<mat-card-content>-->
<!--<form fxLayout="column" fxLayoutAlign="start stretch" [formGroup]="totpForm" (ngSubmit)="registClick()">-->
<!--<mat-form-field class="full-width">-->
<!--<input type="text" id="code" class="input" placeholder="Please enter your code"-->
<!--formControlName="code" required matInput>-->
<!--</mat-form-field>-->
<!--&lt;!&ndash;<div *ngIf="formErrors.email" class="help is-danger">&ndash;&gt;-->
<!--&lt;!&ndash;{{ formErrors.email }}&ndash;&gt;-->
<!--&lt;!&ndash;</div>&ndash;&gt;-->
<!--</form>-->
<!--</mat-card-content>-->
<!--</mat-card>-->
<!--</div>-->

View File

@ -0,0 +1,48 @@
import {
AfterContentInit,
Component,
EventEmitter,
Input,
OnInit,
Output
} from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Store, select } from '@ngrx/store';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import * as TotpStore from 'packages/member/store/totp';
import { AuthSelector } from 'packages/member/store';
import { TotpSelector } from 'packages/member/store';
import { Member } from 'packages/member/model/Member';
import { MemberTotp } from 'packages/member/model/MemberTotp';
@Component({
selector: 'of-config-setting',
templateUrl: './config-setting.component.html',
styleUrls: ['./config-setting.component.scss']
})
export class ConfigSettingComponent implements OnInit, AfterContentInit {
member: Member;
@Input() selectedItem: any;
@Input() totpVO: MemberTotp;
@Output() close = new EventEmitter();
@Input() totpSettingDisplay;
constructor(private activatedRoute: ActivatedRoute,
private router: Router,
private store: Store<TotpStore.State>,
private formBuilder: FormBuilder,
) { }
ngOnInit() {
}
ngAfterContentInit() {
}
onCancel() {
this.close.emit();
}
}

View File

@ -0,0 +1,28 @@
<p-dialog header="{{headerItem}}" [modal]="true" [width]="1200" [(visible)]="totpSettingDisplay" [showHeader]="true" [closeOnEscape]="false">
<of-config-setting [selectedItem]="selectedItem" [totpVO]="totpVO" (close)="onTotpSettingClose()"></of-config-setting>
</p-dialog>
<p-dataView [value]="lists" [paginator]="false" [rows]="5">
<p-header>이중보안</p-header>
<ng-template let-item pTemplate="listItem">
<div class="ui-g" style="padding: 2em;border-bottom: 1px solid #d9d9d9">
<!--<div class="ui-g-12 ui-md-3" style="text-align:left">-->
<!--</div>-->
<div class="ui-g-12 ui-md-8 car-details">
<div class="ui-g">
<div class="ui-g-2 ui-sm-6">{{item.name }} </div>
<div class="ui-g-2 ui-sm-8">{{item.value }}</div>
<div class="ui-g-2 ui-sm-8">{{item.description }}</div>
</div>
</div>
<div class="ui-g-12 ui-md-1 search-icon" style="text-align:right">
<button pButton type="button" label="Add" icon="ui-icon-add" (click)="on2factorConfig($event, item)"></button>
<!--<button pButton type="button" label="Add" icon="ui-icon-add" (click)="selectCar($event, car)"></button>-->
</div>
</div>
</ng-template>
</p-dataView>

View File

@ -0,0 +1,112 @@
import {AfterContentInit, Component, OnInit} from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Store, select } from '@ngrx/store';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import * as TotpStore from 'packages/member/store/totp';
import { AuthSelector } from 'packages/member/store';
import { TotpSelector } from 'packages/member/store';
import { Member } from 'packages/member/model/Member';
import {MemberTotp} from '../../../model/MemberTotp';
@Component({
selector: 'of-settings-totp',
templateUrl: './totp.component.html',
styleUrls: ['./totp.component.scss']
})
export class TotpComponent implements OnInit, AfterContentInit {
member: Member;
selectedItem: any;
totpSettingDisplay = false;
errorMessage: string | null;
totpForm: FormGroup;
headerItem: string;
totpVO: MemberTotp;
formErrors = {
'code': '',
};
lists = [];
constructor(private activatedRoute: ActivatedRoute,
private router: Router,
private store: Store<TotpStore.State>,
private formBuilder: FormBuilder,
) { }
ngOnInit() {
this.totpForm = this.formBuilder.group({
'code': [
[
]
]
});
}
ngAfterContentInit() {
this.store.select(AuthSelector.select('member')).subscribe(
(member: Member) => {
this.member = member;
this.lists = [
{id: 1, name: 'Email', value: this.member.email, description: 'blabla', },
{id: 2, name: 'Phone', value: this.member.phone, description: 'blabla', },
{id: 3, name: 'Google 2factor', value: this.member.totpType, description: 'blabla', },
];
},
(error) => {
console.log(error);
}
);
// this.listStore.select(AuthSelector.select('member')).subscribe(
// (member: Member) => {
// this.store.dispatch(new TotpRegistStore.createTotp(member));
// },
// (error) => {
// console.log(error);
// }
// );
//
// this.probes$.subscribe(
// (probes: boo) => {
// console.log(probes);
// this.dataSource = new MatTableDataSource(probes);
// this.dataSource.sort = this.sort;
// },
// (error: RPCError) => {
// console.log(error.response.message);
// }
// );
}
on2factorConfig(event: Event, item: any) {
this.selectedItem = item;
// server totp regist member info modify
if (this.selectedItem.id === 3) {
this.headerItem = '구글 인증기 설정하기';
this.totpSettingDisplay = true;
// dispatch
}
}
onTotpSettingClose() {
this.totpSettingDisplay = false;
}
registClick() {
const code = this.totpForm.value['code'];
const secretCode = 'X6AWAK573M5372NM';
this.store.select(AuthSelector.select('member')).subscribe(
(member: Member) => {
this.store.dispatch(new TotpStore.Regist({ member, secretCode, code }));
},
(error) => {
console.log(error);
}
);
}
}

View File

@ -8,6 +8,7 @@ import { MemberRESTModule } from './member-rest.module';
import { COMPONENTS } from './component'; import { COMPONENTS } from './component';
import { SERVICES } from './service'; import { SERVICES } from './service';
import { PrimeNGModules } from '../commons/prime-ng/prime-ng.module'; import { PrimeNGModules } from '../commons/prime-ng/prime-ng.module';
import { QRCodeModule } from 'angularx-qrcode';
@NgModule({ @NgModule({
imports: [ imports: [
@ -17,7 +18,8 @@ import { PrimeNGModules } from '../commons/prime-ng/prime-ng.module';
ReactiveFormsModule, ReactiveFormsModule,
MemberStoreModule, MemberStoreModule,
MemberRESTModule, MemberRESTModule,
PrimeNGModules PrimeNGModules,
QRCodeModule,
], ],
declarations: [ declarations: [
COMPONENTS, COMPONENTS,

View File

@ -8,5 +8,6 @@ export interface Member {
phone?: string; phone?: string;
companyName?: string; companyName?: string;
createDate?: Date; createDate?: Date;
totpType?: boolean;
status?: MetaMemberStatus; status?: MetaMemberStatus;
} }

View File

@ -1,5 +1,7 @@
import { MemberService } from './member.service'; import { MemberService } from './member.service';
import {MemberTotpService} from './member-totp.service';
export const SERVICES = [ export const SERVICES = [
MemberService, MemberService,
MemberTotpService,
]; ];

View File

@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
import { RPCService } from '@loafer/ng-rpc/service'; import { RPCService } from '@loafer/ng-rpc/service';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { MemberTotp } from '../model/MemberTotp'; import { MemberTotp } from '../model/MemberTotp';
import { Member } from '../../../member/model'; import { Member } from '../model';
@Injectable() @Injectable()
export class MemberTotpService { export class MemberTotpService {

View File

@ -11,20 +11,24 @@ import { MODULE } from '../member.constant';
import * as AuthStore from './auth'; import * as AuthStore from './auth';
import * as SignupStore from './signup'; import * as SignupStore from './signup';
import * as TotpStore from './totp';
export interface State { export interface State {
auth: AuthStore.State; auth: AuthStore.State;
signup: SignupStore.Signup; signup: SignupStore.Signup;
totp: TotpStore.State;
} }
export const REDUCERS = { export const REDUCERS = {
auth: AuthStore.reducer, auth: AuthStore.reducer,
signup: SignupStore.reducer, signup: SignupStore.reducer,
totp: TotpStore.reducer,
}; };
export const EFFECTS = [ export const EFFECTS = [
AuthStore.Effects, AuthStore.Effects,
SignupStore.Effects, SignupStore.Effects,
TotpStore.Effects,
]; ];
export const selectMemberState = createFeatureSelector<State>(MODULE.name); export const selectMemberState = createFeatureSelector<State>(MODULE.name);
@ -38,3 +42,8 @@ export const SignupSelector = new StateSelector<SignupStore.Signup>(createSelect
selectMemberState, selectMemberState,
(state: State) => state.signup (state: State) => state.signup
)); ));
export const TotpSelector = new StateSelector<TotpStore.State>(createSelector(
selectMemberState,
(state: State) => state.totp
));

View File

@ -2,7 +2,7 @@ import { Action } from '@ngrx/store';
import { RESTClientError } from '@loafer/ng-rest/protocol'; import { RESTClientError } from '@loafer/ng-rest/protocol';
import { Member } from '../../../../member/model'; import { Member } from '../../model';
export enum ActionType { export enum ActionType {
CreateTotp = '[member.totp] CreateTotp', CreateTotp = '[member.totp] CreateTotp',

View File

@ -1,5 +0,0 @@
import { TotpComponent } from './totp/totp.component';
export const COMPONENTS = [
TotpComponent
];

View File

@ -1,39 +0,0 @@
<div fxLayout="row" fxLayoutWrap fxLayoutAlign="center">
<div fxLayout="row" fxLayoutWrap fxLayoutAlign="center">
<mat-card class="example-card">
<mat-card-header>
<mat-card-title>QR Code</mat-card-title>
<!--<mat-card-subtitle>Select Target</mat-card-subtitle>-->
</mat-card-header>
<mat-card-content>
<div fxLayout="row" fxLayoutWrap fxLayoutAlign="left">
<qrcode [qrdata]="'otpauth://totp/overFlow:geekdev@naver.com?secret=X6AWAK573M5372NM'" [size]="128" [level]="'M'"></qrcode>
</div>
</mat-card-content>
</mat-card>
</div>
<div fxLayout="row" fxLayoutWrap fxLayoutAlign="center">
<mat-card class="example-card">
<mat-card-header>
<mat-card-title>Secret Code</mat-card-title>
<mat-card-subtitle>X6AWAK573M5372NM</mat-card-subtitle>
</mat-card-header>
<mat-card-content>
<form fxLayout="column" fxLayoutAlign="start stretch" [formGroup]="totpForm" (ngSubmit)="registClick()">
<mat-form-field class="full-width">
<input type="text" id="code" class="input" placeholder="Please enter your code"
formControlName="code" required matInput>
</mat-form-field>
<!--<div *ngIf="formErrors.email" class="help is-danger">-->
<!--{{ formErrors.email }}-->
<!--</div>-->
</form>
</mat-card-content>
</mat-card>
</div>

View File

@ -1,93 +0,0 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import * as TotpStore from '../../store/totp';
import { Store, select } from '@ngrx/store';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { AuthSelector } from 'packages/member/store';
import { TotpSelector } from '../../store';
import { Member } from 'packages/member/model/Member';
@Component({
selector: 'of-totp',
templateUrl: './totp.component.html',
styleUrls: ['./totp.component.scss']
})
export class TotpComponent implements OnInit {
pending$ = this.store.pipe(select(TotpSelector.select('pending')));
error$ = this.store.pipe(select(TotpSelector.select('error')));
errorMessage: string | null;
totpForm: FormGroup;
formErrors = {
'code': '',
};
constructor(private activatedRoute: ActivatedRoute,
private router: Router,
private store: Store<TotpStore.State>,
private formBuilder: FormBuilder,
) { }
ngOnInit() {
this.totpForm = this.formBuilder.group({
'code': [
[
]
]
})
this.pending$.subscribe((pending: boolean) => {
if (pending) {
this.totpForm.disable();
} else {
this.totpForm.enable();
}
});
this.error$.subscribe((error) => {
if (error) {
this.errorMessage = error.exception;
} else {
this.errorMessage = null;
}
});
}
// ngAfterContentInit() {
//
// this.listStore.select(AuthSelector.select('member')).subscribe(
// (member: Member) => {
// this.store.dispatch(new TotpRegistStore.createTotp(member));
// },
// (error) => {
// console.log(error);
// }
// );
//
// this.probes$.subscribe(
// (probes: boo) => {
// console.log(probes);
// this.dataSource = new MatTableDataSource(probes);
// this.dataSource.sort = this.sort;
// },
// (error: RPCError) => {
// console.log(error.response.message);
// }
// );
//
// }
registClick() {
const code = this.totpForm.value['code'];
const secretCode = 'X6AWAK573M5372NM';
this.store.select(AuthSelector.select('member')).subscribe(
(member: Member) => {
this.store.dispatch(new TotpStore.Regist({ member, secretCode, code }));
},
(error) => {
console.log(error);
}
);
}
}

View File

@ -1,24 +0,0 @@
import { NgModule } from '@angular/core';
import { StoreModule } from '@ngrx/store';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import {
StoreRouterConnectingModule,
RouterStateSerializer,
} from '@ngrx/router-store';
import { EffectsModule } from '@ngrx/effects';
import { combineReducers, ActionReducer, ActionReducerMap, MetaReducer } from '@ngrx/store';
import {
REDUCERS,
EFFECTS,
} from './store';
import { MODULE } from './member-totp.constant';
@NgModule({
imports: [
StoreModule.forFeature(MODULE.name, REDUCERS),
EffectsModule.forFeature(EFFECTS),
],
})
export class MemberTotpStoreModule { }

View File

@ -1,3 +0,0 @@
export const MODULE = {
name: 'member-totp'
};

View File

@ -1,32 +0,0 @@
// import { NgModule } from '@angular/core';
// import { CommonModule } from '@angular/common';
// import {FormsModule, ReactiveFormsModule} from '@angular/forms';
// import { MaterialModule } from 'packages/commons/material/material.module';
// import { QRCodeModule } from 'angularx-qrcode';
// import { COMPONENTS } from './component';
// import { SERVICES } from '../../settings/member/service';
// import { MemberTotpStoreModule } from './member-totp-store.module';
// @NgModule({
// imports: [
// CommonModule,
// FormsModule,
// MaterialModule,
// FormsModule,
// ReactiveFormsModule,
// QRCodeModule,
// MemberTotpStoreModule
// ],
// exports: [
// COMPONENTS,
// ],
// declarations: [
// COMPONENTS,
// ],
// providers: [
// SERVICES,
// ],
// })
// export class MemberTotpModule { }

View File

@ -1,5 +0,0 @@
import { MemberTotpService } from './member-totp.service';
export const SERVICES = [
MemberTotpService,
];

View File

@ -1,31 +0,0 @@
import {
createSelector,
createFeatureSelector,
ActionReducerMap,
} from '@ngrx/store';
import { StateSelector } from 'packages/core/ngrx/store';
import { MODULE } from '../member-totp.constant';
import * as TotpStore from './totp';
export interface State {
totp: TotpStore.State;
}
export const REDUCERS = {
totp: TotpStore.reducer,
};
export const EFFECTS = [
TotpStore.Effects,
];
export const selectMemberTotpState = createFeatureSelector<State>(MODULE.name);
export const TotpSelector = new StateSelector<TotpStore.State>(createSelector(
selectMemberTotpState,
(state: State) => state.totp
));