From a903d5c0c199e9c64ddc1965f91f8c9b8d847bed Mon Sep 17 00:00:00 2001 From: FlyersWeb Date: Fri, 13 Dec 2019 12:15:43 +0100 Subject: [PATCH 1/2] do not store secret in localStorage for security purpose --- .../src/app/login/login.component.spec.ts | 19 +++-- front-end/src/app/login/login.component.ts | 76 ++++++++++--------- front-end/src/app/token.service.spec.ts | 8 +- front-end/src/app/token.service.ts | 68 +++++++++-------- 4 files changed, 90 insertions(+), 81 deletions(-) diff --git a/front-end/src/app/login/login.component.spec.ts b/front-end/src/app/login/login.component.spec.ts index 2e6b979..e92ed4d 100644 --- a/front-end/src/app/login/login.component.spec.ts +++ b/front-end/src/app/login/login.component.spec.ts @@ -1,11 +1,11 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; -import { LoginComponent } from './login.component'; -import { ReactiveFormsModule } from '@angular/forms'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { RouterTestingModule } from '@angular/router/testing'; +import { LoginComponent } from "./login.component"; +import { ReactiveFormsModule } from "@angular/forms"; +import { HttpClientTestingModule } from "@angular/common/http/testing"; +import { RouterTestingModule } from "@angular/router/testing"; -describe('LoginComponent', () => { +describe("LoginComponent", () => { let component: LoginComponent; let fixture: ComponentFixture; @@ -16,9 +16,8 @@ describe('LoginComponent', () => { HttpClientTestingModule, RouterTestingModule ], - declarations: [ LoginComponent ] - }) - .compileComponents(); + declarations: [LoginComponent] + }).compileComponents(); })); beforeEach(() => { @@ -27,7 +26,7 @@ describe('LoginComponent', () => { fixture.detectChanges(); }); - it('should create', () => { + it("should create", () => { expect(component).toBeTruthy(); }); }); diff --git a/front-end/src/app/login/login.component.ts b/front-end/src/app/login/login.component.ts index 7fed738..99e5764 100644 --- a/front-end/src/app/login/login.component.ts +++ b/front-end/src/app/login/login.component.ts @@ -1,18 +1,17 @@ -import { Component, OnInit } from '@angular/core'; -import { FormGroup, FormControl } from '@angular/forms'; -import { Router } from '@angular/router'; - -import { WSSEService } from '../wsse.service'; -import { TokenService } from '../token.service'; -import { Observable } from 'rxjs'; -import { flatMap } from 'rxjs/operators'; -import { HttpErrorResponse } from '@angular/common/http'; +import { Component, OnInit } from "@angular/core"; +import { FormGroup, FormControl } from "@angular/forms"; +import { Router } from "@angular/router"; +import { WSSEService } from "../wsse.service"; +import { TokenService } from "../token.service"; +import { Observable } from "rxjs"; +import { flatMap } from "rxjs/operators"; +import { HttpErrorResponse } from "@angular/common/http"; @Component({ - selector: 'app-login', - templateUrl: './login.component.html', - styleUrls: ['./login.component.css'] + selector: "app-login", + templateUrl: "./login.component.html", + styleUrls: ["./login.component.css"] }) export class LoginComponent implements OnInit { $login: Observable<{ secret?: string }>; @@ -22,52 +21,57 @@ export class LoginComponent implements OnInit { error: string; credentialsForm = new FormGroup({ - username: new FormControl(''), - password: new FormControl(''), + username: new FormControl(""), + password: new FormControl("") }); constructor( private wsseService: WSSEService, private tokenService: TokenService, - private router: Router, - ) { } + private router: Router + ) {} ngOnInit() { if (this.tokenService.hasAuthorizationToken()) { - this.username = localStorage.getItem('WSSE-Username'); - this.created = localStorage.getItem('WSSE-CreatedAt'); - this.secret = localStorage.getItem('WSSE-Secret'); + this.username = this.tokenService.username; + this.created = this.tokenService.created; + this.secret = this.tokenService.secret; } } onSubmit() { - let credentials: { username: string, password: string } = this.credentialsForm.value; + let credentials: { username: string; password: string } = this + .credentialsForm.value; // Login should return user secret (hashed password) this.$login = this.wsseService.postCredentials(credentials); - this.$login - .subscribe( - // Show generated token - ({ secret }) => { - this.username = credentials.username; - this.created = this.tokenService.formatDate(new Date()); - this.secret = secret; + this.$login.subscribe( + // Show generated token + ({ secret }) => { + this.username = credentials.username; + this.created = this.tokenService.formatDate(new Date()); + this.secret = secret; - let authToken = this.tokenService.generateWSSEToken(this.username, this.created, this.secret); + let authToken = this.tokenService.generateWSSEToken( + this.username, + this.created, + this.secret + ); - console.log(`Generated WSSE Token ${authToken}`); - }, - // Show server error - (error: HttpErrorResponse) => { - console.error(error); - this.error = error.message; - }); + console.log(`Generated WSSE Token ${authToken}`); + }, + // Show server error + (error: HttpErrorResponse) => { + console.error(error); + this.error = error.message; + } + ); } onLogout() { this.tokenService.cleanAuthorizationToken(); this.secret = null; - return this.router.navigate(['']); + return this.router.navigate([""]); } } diff --git a/front-end/src/app/token.service.spec.ts b/front-end/src/app/token.service.spec.ts index 9375546..b102694 100644 --- a/front-end/src/app/token.service.spec.ts +++ b/front-end/src/app/token.service.spec.ts @@ -1,11 +1,11 @@ -import { TestBed } from '@angular/core/testing'; +import { TestBed } from "@angular/core/testing"; -import { TokenService } from './token.service'; +import { TokenService } from "./token.service"; -describe('TokenService', () => { +describe("TokenService", () => { beforeEach(() => TestBed.configureTestingModule({})); - it('should be created', () => { + it("should be created", () => { const service: TokenService = TestBed.get(TokenService); expect(service).toBeTruthy(); }); diff --git a/front-end/src/app/token.service.ts b/front-end/src/app/token.service.ts index 7df28a2..bcb6fa4 100644 --- a/front-end/src/app/token.service.ts +++ b/front-end/src/app/token.service.ts @@ -1,31 +1,33 @@ -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; +import { Injectable } from "@angular/core"; +import { Observable } from "rxjs"; -import CryptoJS from 'crypto-js'; -import randomString from 'random-string'; +import CryptoJS from "crypto-js"; +import randomString from "random-string"; @Injectable({ - providedIn: 'root' + providedIn: "root" }) export class TokenService { - + username: string; + created: string; + secret: string; wsseToken: string; - constructor() { } + constructor() {} hasAuthorizationToken(): Boolean { - let hasUsername = new Boolean(localStorage.getItem('WSSE-Username')); - let hasCreated = new Boolean(localStorage.getItem('WSSE-CreatedAt')); - let hasSecret = new Boolean(localStorage.getItem('WSSE-Secret')); + const hasUsername = new Boolean(this.username); + const hasCreated = new Boolean(this.created); + const hasSecret = new Boolean(this.secret); return hasUsername && hasCreated && hasSecret; } getAuthorizationToken(): string | null { // Generate a new token with new nonce each time otherwise it's a replay attack - let username = localStorage.getItem('WSSE-Username'); - let created = localStorage.getItem('WSSE-CreatedAt'); - let secret = localStorage.getItem('WSSE-Secret'); + let username = this.username; + let created = this.created; + let secret = this.secret; if (!username || !created || !secret) { return null; @@ -36,36 +38,41 @@ export class TokenService { setAuthorizationToken(username: string, created: string, secret: string) { // Save static parts of the token - localStorage.setItem('WSSE-Username', username); - localStorage.setItem('WSSE-CreatedAt', created); - localStorage.setItem('WSSE-Secret', secret); + this.username = username; + this.created = created; + this.secret = secret; } cleanAuthorizationToken() { // Clean token informations - localStorage.removeItem('WSSE-Username'); - localStorage.removeItem('WSSE-CreatedAt'); - localStorage.removeItem('WSSE-Secret'); + this.username = null; + this.created = null; + this.secret = null; } formatDate(d: Date): string { // Padding for date creation - let pad = function (num: number): string { + let pad = function(num: number): string { return ("0" + num).slice(-2); }; - return [ - d.getUTCFullYear(), - pad(d.getUTCMonth() + 1), - pad(d.getUTCDate())].join("-") + "T" + - [pad(d.getUTCHours()), - pad(d.getUTCMinutes()), - pad(d.getUTCSeconds())].join(":") + "Z"; + return ( + [d.getUTCFullYear(), pad(d.getUTCMonth() + 1), pad(d.getUTCDate())].join( + "-" + ) + + "T" + + [ + pad(d.getUTCHours()), + pad(d.getUTCMinutes()), + pad(d.getUTCSeconds()) + ].join(":") + + "Z" + ); } generateWSSEToken(username: string, created: string, secret: string): string { if (!username || !created || !secret) { - throw new Error('missing secret'); + throw new Error("missing secret"); } // Should store username and created and secret in localStorage in order to regenerate token @@ -75,16 +82,15 @@ export class TokenService { let nonce = randomString({ length: 30, numeric: true, - letters: true, + letters: true }); - // Generating digest from secret, creation and nonce let hash = CryptoJS.SHA1(nonce + created + secret); let digest = hash.toString(CryptoJS.enc.Base64); // Base64 Encode digest - let b64nonce = CryptoJS.enc.Utf8.parse(nonce).toString(CryptoJS.enc.Base64); + let b64nonce = CryptoJS.enc.Utf8.parse(nonce).toString(CryptoJS.enc.Base64); // Return generated token return `UsernameToken Username="${username}", PasswordDigest="${digest}", Nonce="${b64nonce}", Created="${created}"`; From ecded5ac2a1ffc5aad54e01e6f29ecbd29851fec Mon Sep 17 00:00:00 2001 From: FlyersWeb Date: Fri, 13 Dec 2019 12:16:02 +0100 Subject: [PATCH 2/2] format front code --- front-end/src/app/app-routing.module.ts | 21 ++-- front-end/src/app/app.component.spec.ts | 29 +++--- front-end/src/app/app.component.ts | 4 +- front-end/src/app/app.module.ts | 32 +++---- .../src/app/hello/hello.component.spec.ts | 38 ++++---- front-end/src/app/hello/hello.component.ts | 43 ++++----- front-end/src/app/http-interceptor/index.ts | 8 +- .../app/http-interceptor/wsse-interceptor.ts | 23 +++-- .../src/app/login/login.component.spec.ts | 36 +++---- front-end/src/app/login/login.component.ts | 78 +++++++-------- front-end/src/app/token.service.spec.ts | 18 ++-- front-end/src/app/token.service.ts | 96 ++++++++++--------- front-end/src/app/wsse.service.spec.ts | 24 ++--- front-end/src/app/wsse.service.ts | 27 +++--- .../src/environments/environment.prod.ts | 6 +- front-end/src/environments/environment.ts | 6 +- front-end/src/main.ts | 15 +-- front-end/src/polyfills.ts | 3 +- front-end/src/test.ts | 14 +-- 19 files changed, 252 insertions(+), 269 deletions(-) diff --git a/front-end/src/app/app-routing.module.ts b/front-end/src/app/app-routing.module.ts index 8a3384d..5327ef9 100644 --- a/front-end/src/app/app-routing.module.ts +++ b/front-end/src/app/app-routing.module.ts @@ -1,18 +1,15 @@ -import { NgModule } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; -import { LoginComponent } from './login/login.component'; -import { HelloComponent } from './hello/hello.component'; - +import { NgModule } from '@angular/core' +import { Routes, RouterModule } from '@angular/router' +import { LoginComponent } from './login/login.component' +import { HelloComponent } from './hello/hello.component' const routes: Routes = [ - { path: '', component: LoginComponent}, - { path: 'hello', component: HelloComponent} -]; + { path: '', component: LoginComponent }, + { path: 'hello', component: HelloComponent } +] @NgModule({ - imports: [RouterModule.forRoot( - routes - )], + imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) -export class AppRoutingModule { } +export class AppRoutingModule {} diff --git a/front-end/src/app/app.component.spec.ts b/front-end/src/app/app.component.spec.ts index 9c11e34..a19b738 100644 --- a/front-end/src/app/app.component.spec.ts +++ b/front-end/src/app/app.component.spec.ts @@ -1,23 +1,18 @@ -import { TestBed, async } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; -import { AppComponent } from './app.component'; +import { TestBed, async } from '@angular/core/testing' +import { RouterTestingModule } from '@angular/router/testing' +import { AppComponent } from './app.component' describe('AppComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ - RouterTestingModule - ], - declarations: [ - AppComponent - ], - }).compileComponents(); - })); + imports: [RouterTestingModule], + declarations: [AppComponent] + }).compileComponents() + })) it('should create the app', () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.debugElement.componentInstance; - expect(app).toBeTruthy(); - }); - -}); + const fixture = TestBed.createComponent(AppComponent) + const app = fixture.debugElement.componentInstance + expect(app).toBeTruthy() + }) +}) diff --git a/front-end/src/app/app.component.ts b/front-end/src/app/app.component.ts index 9a4bf61..acb25fc 100644 --- a/front-end/src/app/app.component.ts +++ b/front-end/src/app/app.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { Component } from '@angular/core' @Component({ selector: 'app-root', @@ -6,5 +6,5 @@ import { Component } from '@angular/core'; styleUrls: ['./app.component.css'] }) export class AppComponent { - title = 'Angular Symfony'; + title = 'Angular Symfony' } diff --git a/front-end/src/app/app.module.ts b/front-end/src/app/app.module.ts index 2cf6fcd..96be3e6 100644 --- a/front-end/src/app/app.module.ts +++ b/front-end/src/app/app.module.ts @@ -1,29 +1,23 @@ -import { BrowserModule } from '@angular/platform-browser'; -import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser' +import { NgModule } from '@angular/core' -import { AppRoutingModule } from './app-routing.module'; -import { ReactiveFormsModule } from '@angular/forms'; -import { HttpClientModule } from '@angular/common/http'; -import { AppComponent } from './app.component'; -import { LoginComponent } from './login/login.component'; -import { HelloComponent } from './hello/hello.component'; -import { httpInterceptorProviders } from './http-interceptor'; +import { AppRoutingModule } from './app-routing.module' +import { ReactiveFormsModule } from '@angular/forms' +import { HttpClientModule } from '@angular/common/http' +import { AppComponent } from './app.component' +import { LoginComponent } from './login/login.component' +import { HelloComponent } from './hello/hello.component' +import { httpInterceptorProviders } from './http-interceptor' @NgModule({ - declarations: [ - AppComponent, - LoginComponent, - HelloComponent - ], + declarations: [AppComponent, LoginComponent, HelloComponent], imports: [ BrowserModule, AppRoutingModule, ReactiveFormsModule, - HttpClientModule, - ], - providers: [ - httpInterceptorProviders + HttpClientModule ], + providers: [httpInterceptorProviders], bootstrap: [AppComponent] }) -export class AppModule { } +export class AppModule {} diff --git a/front-end/src/app/hello/hello.component.spec.ts b/front-end/src/app/hello/hello.component.spec.ts index 34d56f6..05d4ac8 100644 --- a/front-end/src/app/hello/hello.component.spec.ts +++ b/front-end/src/app/hello/hello.component.spec.ts @@ -1,31 +1,27 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { RouterTestingModule } from '@angular/router/testing'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing' +import { HttpClientTestingModule } from '@angular/common/http/testing' +import { RouterTestingModule } from '@angular/router/testing' -import { HelloComponent } from './hello.component'; +import { HelloComponent } from './hello.component' describe('HelloComponent', () => { - let component: HelloComponent; - let fixture: ComponentFixture; + let component: HelloComponent + let fixture: ComponentFixture beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ - HttpClientTestingModule, - RouterTestingModule, - ], - declarations: [ HelloComponent ] - }) - .compileComponents(); - })); + imports: [HttpClientTestingModule, RouterTestingModule], + declarations: [HelloComponent] + }).compileComponents() + })) beforeEach(() => { - fixture = TestBed.createComponent(HelloComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(HelloComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/front-end/src/app/hello/hello.component.ts b/front-end/src/app/hello/hello.component.ts index 3137aaa..bf7d6fd 100644 --- a/front-end/src/app/hello/hello.component.ts +++ b/front-end/src/app/hello/hello.component.ts @@ -1,10 +1,10 @@ -import { Component, OnInit } from '@angular/core'; -import { Observable } from 'rxjs'; +import { Component, OnInit } from '@angular/core' +import { Observable } from 'rxjs' -import { WSSEService } from '../wsse.service'; -import { HttpErrorResponse } from '@angular/common/http'; -import { Router } from '@angular/router'; -import { TokenService } from '../token.service'; +import { WSSEService } from '../wsse.service' +import { HttpErrorResponse } from '@angular/common/http' +import { Router } from '@angular/router' +import { TokenService } from '../token.service' @Component({ selector: 'app-hello', @@ -12,37 +12,36 @@ import { TokenService } from '../token.service'; styleUrls: ['./hello.component.css'] }) export class HelloComponent implements OnInit { + $hello: Observable<{ hello?: string }> + helloMessage: string - $hello: Observable<{ hello?: string }>; - helloMessage: string; - - constructor( + constructor ( private wsseService: WSSEService, private tokenService: TokenService, - private router: Router, - ) { } + private router: Router + ) {} - ngOnInit() { + ngOnInit () { // Example API call showing an Hello World - this.$hello = this.wsseService.getHello(); + this.$hello = this.wsseService.getHello() this.$hello.subscribe( // Show API response ({ hello }) => { - console.log(`Received from server ${hello}`); - this.helloMessage = hello; + console.log(`Received from server ${hello}`) + this.helloMessage = hello }, // Log error message and redirect to login (error: HttpErrorResponse) => { - console.error(error); + console.error(error) if (error.status === 401) { - return this.router.navigate(['']); + return this.router.navigate(['']) } - }); + } + ) } - onGoBack() { - return this.router.navigate(['']); + onGoBack () { + return this.router.navigate(['']) } - } diff --git a/front-end/src/app/http-interceptor/index.ts b/front-end/src/app/http-interceptor/index.ts index 4e3b1b8..e542f73 100644 --- a/front-end/src/app/http-interceptor/index.ts +++ b/front-end/src/app/http-interceptor/index.ts @@ -1,8 +1,8 @@ -import { HTTP_INTERCEPTORS } from '@angular/common/http'; +import { HTTP_INTERCEPTORS } from '@angular/common/http' -import { WSSEInterceptor } from './wsse-interceptor'; +import { WSSEInterceptor } from './wsse-interceptor' /** Http interceptor providers in outside-in order */ export const httpInterceptorProviders = [ - { provide: HTTP_INTERCEPTORS, useClass: WSSEInterceptor, multi: true }, -]; \ No newline at end of file + { provide: HTTP_INTERCEPTORS, useClass: WSSEInterceptor, multi: true } +] diff --git a/front-end/src/app/http-interceptor/wsse-interceptor.ts b/front-end/src/app/http-interceptor/wsse-interceptor.ts index 36ecd50..94eacbb 100644 --- a/front-end/src/app/http-interceptor/wsse-interceptor.ts +++ b/front-end/src/app/http-interceptor/wsse-interceptor.ts @@ -1,26 +1,25 @@ -import { TokenService } from '../token.service'; -import { Injectable } from '@angular/core'; -import { HttpInterceptor, HttpRequest, HttpHandler } from '@angular/common/http'; +import { TokenService } from '../token.service' +import { Injectable } from '@angular/core' +import { HttpInterceptor, HttpRequest, HttpHandler } from '@angular/common/http' @Injectable() export class WSSEInterceptor implements HttpInterceptor { + constructor (private tokenService: TokenService) {} - constructor(private tokenService: TokenService) {} - - intercept(req: HttpRequest, next: HttpHandler) { - let authToken = this.tokenService.getAuthorizationToken(); + intercept (req: HttpRequest, next: HttpHandler) { + let authToken = this.tokenService.getAuthorizationToken() if (authToken) { // Clone the request and replace the original headers with - // cloned headers, updated with the authorization. + // cloned headers, updated with the authorization. const authReq = req.clone({ headers: req.headers.set('X-WSSE', authToken) - }); + }) // send cloned request with header to the next handler. - return next.handle(authReq); + return next.handle(authReq) } else { // otherwise send request without token - return next.handle(req); + return next.handle(req) } } -} \ No newline at end of file +} diff --git a/front-end/src/app/login/login.component.spec.ts b/front-end/src/app/login/login.component.spec.ts index e92ed4d..aacf088 100644 --- a/front-end/src/app/login/login.component.spec.ts +++ b/front-end/src/app/login/login.component.spec.ts @@ -1,13 +1,13 @@ -import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { async, ComponentFixture, TestBed } from '@angular/core/testing' -import { LoginComponent } from "./login.component"; -import { ReactiveFormsModule } from "@angular/forms"; -import { HttpClientTestingModule } from "@angular/common/http/testing"; -import { RouterTestingModule } from "@angular/router/testing"; +import { LoginComponent } from './login.component' +import { ReactiveFormsModule } from '@angular/forms' +import { HttpClientTestingModule } from '@angular/common/http/testing' +import { RouterTestingModule } from '@angular/router/testing' -describe("LoginComponent", () => { - let component: LoginComponent; - let fixture: ComponentFixture; +describe('LoginComponent', () => { + let component: LoginComponent + let fixture: ComponentFixture beforeEach(async(() => { TestBed.configureTestingModule({ @@ -17,16 +17,16 @@ describe("LoginComponent", () => { RouterTestingModule ], declarations: [LoginComponent] - }).compileComponents(); - })); + }).compileComponents() + })) beforeEach(() => { - fixture = TestBed.createComponent(LoginComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(LoginComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) - it("should create", () => { - expect(component).toBeTruthy(); - }); -}); + it('should create', () => { + expect(component).toBeTruthy() + }) +}) diff --git a/front-end/src/app/login/login.component.ts b/front-end/src/app/login/login.component.ts index 99e5764..fd68efb 100644 --- a/front-end/src/app/login/login.component.ts +++ b/front-end/src/app/login/login.component.ts @@ -1,77 +1,77 @@ -import { Component, OnInit } from "@angular/core"; -import { FormGroup, FormControl } from "@angular/forms"; -import { Router } from "@angular/router"; +import { Component, OnInit } from '@angular/core' +import { FormGroup, FormControl } from '@angular/forms' +import { Router } from '@angular/router' -import { WSSEService } from "../wsse.service"; -import { TokenService } from "../token.service"; -import { Observable } from "rxjs"; -import { flatMap } from "rxjs/operators"; -import { HttpErrorResponse } from "@angular/common/http"; +import { WSSEService } from '../wsse.service' +import { TokenService } from '../token.service' +import { Observable } from 'rxjs' +import { flatMap } from 'rxjs/operators' +import { HttpErrorResponse } from '@angular/common/http' @Component({ - selector: "app-login", - templateUrl: "./login.component.html", - styleUrls: ["./login.component.css"] + selector: 'app-login', + templateUrl: './login.component.html', + styleUrls: ['./login.component.css'] }) export class LoginComponent implements OnInit { - $login: Observable<{ secret?: string }>; - username: string; - secret: string; - created: string; - error: string; + $login: Observable<{ secret?: string }> + username: string + secret: string + created: string + error: string credentialsForm = new FormGroup({ - username: new FormControl(""), - password: new FormControl("") - }); + username: new FormControl(''), + password: new FormControl('') + }) - constructor( + constructor ( private wsseService: WSSEService, private tokenService: TokenService, private router: Router ) {} - ngOnInit() { + ngOnInit () { if (this.tokenService.hasAuthorizationToken()) { - this.username = this.tokenService.username; - this.created = this.tokenService.created; - this.secret = this.tokenService.secret; + this.username = this.tokenService.username + this.created = this.tokenService.created + this.secret = this.tokenService.secret } } - onSubmit() { + onSubmit () { let credentials: { username: string; password: string } = this - .credentialsForm.value; + .credentialsForm.value // Login should return user secret (hashed password) - this.$login = this.wsseService.postCredentials(credentials); + this.$login = this.wsseService.postCredentials(credentials) this.$login.subscribe( // Show generated token ({ secret }) => { - this.username = credentials.username; - this.created = this.tokenService.formatDate(new Date()); - this.secret = secret; + this.username = credentials.username + this.created = this.tokenService.formatDate(new Date()) + this.secret = secret let authToken = this.tokenService.generateWSSEToken( this.username, this.created, this.secret - ); + ) - console.log(`Generated WSSE Token ${authToken}`); + console.log(`Generated WSSE Token ${authToken}`) }, // Show server error (error: HttpErrorResponse) => { - console.error(error); - this.error = error.message; + console.error(error) + this.error = error.message } - ); + ) } - onLogout() { - this.tokenService.cleanAuthorizationToken(); - this.secret = null; - return this.router.navigate([""]); + onLogout () { + this.tokenService.cleanAuthorizationToken() + this.secret = null + return this.router.navigate(['']) } } diff --git a/front-end/src/app/token.service.spec.ts b/front-end/src/app/token.service.spec.ts index b102694..187d967 100644 --- a/front-end/src/app/token.service.spec.ts +++ b/front-end/src/app/token.service.spec.ts @@ -1,12 +1,12 @@ -import { TestBed } from "@angular/core/testing"; +import { TestBed } from '@angular/core/testing' -import { TokenService } from "./token.service"; +import { TokenService } from './token.service' -describe("TokenService", () => { - beforeEach(() => TestBed.configureTestingModule({})); +describe('TokenService', () => { + beforeEach(() => TestBed.configureTestingModule({})) - it("should be created", () => { - const service: TokenService = TestBed.get(TokenService); - expect(service).toBeTruthy(); - }); -}); + it('should be created', () => { + const service: TokenService = TestBed.get(TokenService) + expect(service).toBeTruthy() + }) +}) diff --git a/front-end/src/app/token.service.ts b/front-end/src/app/token.service.ts index bcb6fa4..4da5ab8 100644 --- a/front-end/src/app/token.service.ts +++ b/front-end/src/app/token.service.ts @@ -1,98 +1,102 @@ -import { Injectable } from "@angular/core"; -import { Observable } from "rxjs"; +import { Injectable } from '@angular/core' +import { Observable } from 'rxjs' -import CryptoJS from "crypto-js"; -import randomString from "random-string"; +import CryptoJS from 'crypto-js' +import randomString from 'random-string' @Injectable({ - providedIn: "root" + providedIn: 'root' }) export class TokenService { - username: string; - created: string; - secret: string; - wsseToken: string; + username: string + created: string + secret: string + wsseToken: string - constructor() {} + constructor () {} - hasAuthorizationToken(): Boolean { - const hasUsername = new Boolean(this.username); - const hasCreated = new Boolean(this.created); - const hasSecret = new Boolean(this.secret); + hasAuthorizationToken (): Boolean { + const hasUsername = new Boolean(this.username) + const hasCreated = new Boolean(this.created) + const hasSecret = new Boolean(this.secret) - return hasUsername && hasCreated && hasSecret; + return hasUsername && hasCreated && hasSecret } - getAuthorizationToken(): string | null { + getAuthorizationToken (): string | null { // Generate a new token with new nonce each time otherwise it's a replay attack - let username = this.username; - let created = this.created; - let secret = this.secret; + let username = this.username + let created = this.created + let secret = this.secret if (!username || !created || !secret) { - return null; + return null } - return this.generateWSSEToken(username, created, secret); + return this.generateWSSEToken(username, created, secret) } - setAuthorizationToken(username: string, created: string, secret: string) { + setAuthorizationToken (username: string, created: string, secret: string) { // Save static parts of the token - this.username = username; - this.created = created; - this.secret = secret; + this.username = username + this.created = created + this.secret = secret } - cleanAuthorizationToken() { + cleanAuthorizationToken () { // Clean token informations - this.username = null; - this.created = null; - this.secret = null; + this.username = null + this.created = null + this.secret = null } - formatDate(d: Date): string { + formatDate (d: Date): string { // Padding for date creation - let pad = function(num: number): string { - return ("0" + num).slice(-2); - }; + let pad = function (num: number): string { + return ('0' + num).slice(-2) + } return ( [d.getUTCFullYear(), pad(d.getUTCMonth() + 1), pad(d.getUTCDate())].join( - "-" + '-' ) + - "T" + + 'T' + [ pad(d.getUTCHours()), pad(d.getUTCMinutes()), pad(d.getUTCSeconds()) - ].join(":") + - "Z" - ); + ].join(':') + + 'Z' + ) } - generateWSSEToken(username: string, created: string, secret: string): string { + generateWSSEToken ( + username: string, + created: string, + secret: string + ): string { if (!username || !created || !secret) { - throw new Error("missing secret"); + throw new Error('missing secret') } // Should store username and created and secret in localStorage in order to regenerate token - this.setAuthorizationToken(username, created, secret); + this.setAuthorizationToken(username, created, secret) // Generate nonce let nonce = randomString({ length: 30, numeric: true, letters: true - }); + }) // Generating digest from secret, creation and nonce - let hash = CryptoJS.SHA1(nonce + created + secret); - let digest = hash.toString(CryptoJS.enc.Base64); + let hash = CryptoJS.SHA1(nonce + created + secret) + let digest = hash.toString(CryptoJS.enc.Base64) // Base64 Encode digest - let b64nonce = CryptoJS.enc.Utf8.parse(nonce).toString(CryptoJS.enc.Base64); + let b64nonce = CryptoJS.enc.Utf8.parse(nonce).toString(CryptoJS.enc.Base64) // Return generated token - return `UsernameToken Username="${username}", PasswordDigest="${digest}", Nonce="${b64nonce}", Created="${created}"`; + return `UsernameToken Username="${username}", PasswordDigest="${digest}", Nonce="${b64nonce}", Created="${created}"` } } diff --git a/front-end/src/app/wsse.service.spec.ts b/front-end/src/app/wsse.service.spec.ts index 39527f6..592efe9 100644 --- a/front-end/src/app/wsse.service.spec.ts +++ b/front-end/src/app/wsse.service.spec.ts @@ -1,17 +1,17 @@ -import { TestBed } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing' -import { WSSEService } from './wsse.service'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { WSSEService } from './wsse.service' +import { HttpClientTestingModule } from '@angular/common/http/testing' describe('WSSEService', () => { - beforeEach(() => TestBed.configureTestingModule({ - imports: [ - HttpClientTestingModule, - ] - })); + beforeEach(() => + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule] + }) + ) it('should be created', () => { - const service: WSSEService = TestBed.get(WSSEService); - expect(service).toBeTruthy(); - }); -}); + const service: WSSEService = TestBed.get(WSSEService) + expect(service).toBeTruthy() + }) +}) diff --git a/front-end/src/app/wsse.service.ts b/front-end/src/app/wsse.service.ts index 008ecc0..a9cca79 100644 --- a/front-end/src/app/wsse.service.ts +++ b/front-end/src/app/wsse.service.ts @@ -1,29 +1,28 @@ -import { Injectable } from '@angular/core'; +import { Injectable } from '@angular/core' -import { HttpClient } from '@angular/common/http'; +import { HttpClient } from '@angular/common/http' -import { environment } from '../environments/environment'; -import { Observable } from 'rxjs'; +import { environment } from '../environments/environment' +import { Observable } from 'rxjs' interface credentialsType { - username: string; - password: string; + username: string + password: string } @Injectable({ providedIn: 'root' }) export class WSSEService { + constructor (private httpClient: HttpClient) {} - constructor( - private httpClient: HttpClient - ) { } - - postCredentials(credentials: credentialsType) : Observable<{secret?: string}> { - return this.httpClient.post(environment.server + '/login', credentials); + postCredentials ( + credentials: credentialsType + ): Observable<{ secret?: string }> { + return this.httpClient.post(environment.server + '/login', credentials) } - getHello() : Observable<{hello?: string}> { - return this.httpClient.get(environment.server + '/api/hello'); + getHello (): Observable<{ hello?: string }> { + return this.httpClient.get(environment.server + '/api/hello') } } diff --git a/front-end/src/environments/environment.prod.ts b/front-end/src/environments/environment.prod.ts index 6c68604..ab8d4b0 100644 --- a/front-end/src/environments/environment.prod.ts +++ b/front-end/src/environments/environment.prod.ts @@ -1,4 +1,4 @@ export const environment = { - server: "http://0.0.0.0:8000", - production: true, -}; + server: 'http://0.0.0.0:8000', + production: true +} diff --git a/front-end/src/environments/environment.ts b/front-end/src/environments/environment.ts index ccb9fd0..7f3f51a 100644 --- a/front-end/src/environments/environment.ts +++ b/front-end/src/environments/environment.ts @@ -3,9 +3,9 @@ // The list of file replacements can be found in `angular.json`. export const environment = { - server: "http://0.0.0.0:8000", - production: false, -}; + server: 'http://0.0.0.0:8000', + production: false +} /* * For easier debugging in development mode, you can import the following file diff --git a/front-end/src/main.ts b/front-end/src/main.ts index c7b673c..11a2158 100644 --- a/front-end/src/main.ts +++ b/front-end/src/main.ts @@ -1,12 +1,13 @@ -import { enableProdMode } from '@angular/core'; -import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { enableProdMode } from '@angular/core' +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic' -import { AppModule } from './app/app.module'; -import { environment } from './environments/environment'; +import { AppModule } from './app/app.module' +import { environment } from './environments/environment' if (environment.production) { - enableProdMode(); + enableProdMode() } -platformBrowserDynamic().bootstrapModule(AppModule) - .catch(err => console.error(err)); +platformBrowserDynamic() + .bootstrapModule(AppModule) + .catch(err => console.error(err)) diff --git a/front-end/src/polyfills.ts b/front-end/src/polyfills.ts index aa665d6..40a367c 100644 --- a/front-end/src/polyfills.ts +++ b/front-end/src/polyfills.ts @@ -55,8 +55,7 @@ /*************************************************************************************************** * Zone JS is required by default for Angular itself. */ -import 'zone.js/dist/zone'; // Included with Angular CLI. - +import 'zone.js/dist/zone' // Included with Angular CLI. /*************************************************************************************************** * APPLICATION IMPORTS diff --git a/front-end/src/test.ts b/front-end/src/test.ts index 1631789..8f0b36c 100644 --- a/front-end/src/test.ts +++ b/front-end/src/test.ts @@ -1,20 +1,20 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files -import 'zone.js/dist/zone-testing'; -import { getTestBed } from '@angular/core/testing'; +import 'zone.js/dist/zone-testing' +import { getTestBed } from '@angular/core/testing' import { BrowserDynamicTestingModule, platformBrowserDynamicTesting -} from '@angular/platform-browser-dynamic/testing'; +} from '@angular/platform-browser-dynamic/testing' -declare const require: any; +declare const require: any // First, initialize the Angular testing environment. getTestBed().initTestEnvironment( BrowserDynamicTestingModule, platformBrowserDynamicTesting() -); +) // Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); +const context = require.context('./', true, /\.spec\.ts$/) // And load the modules. -context.keys().map(context); +context.keys().map(context)