before update

This commit is contained in:
VLE2FE 2020-05-20 10:07:34 +02:00
parent 7f47af425d
commit 7cc6147a25
16 changed files with 1324 additions and 1760 deletions

View File

@ -68,7 +68,8 @@
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "UI:build"
"browserTarget": "UI:build",
"proxyConfig": "src/proxy.conf.json"
},
"configurations": {
"production": {

2869
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -22,19 +22,20 @@
"@angular/router": "~8.2.14",
"@hapi/joi": "^17.1.1",
"@inst-iot/bosch-angular-ui-components": "^0.5.30",
"angular-2-local-storage": "^3.0.2",
"flatpickr": "^4.6.3",
"rxjs": "~6.4.0",
"tslib": "^1.10.0",
"zone.js": "~0.9.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.803.22",
"@angular-devkit/build-angular": "^0.803.25",
"@angular/cli": "~8.3.22",
"@angular/compiler-cli": "~8.2.14",
"@angular/language-service": "~8.2.14",
"@types/node": "~8.9.4",
"@types/jasmine": "~3.3.8",
"@types/jasminewd2": "~2.0.3",
"@types/node": "~8.9.4",
"codelyzer": "^5.0.0",
"jasmine-core": "~3.4.0",
"jasmine-spec-reporter": "~4.2.1",

View File

@ -0,0 +1,14 @@
import { TestBed } from '@angular/core/testing';
import { ApiService } from './api.service';
describe('ApiService', () => {
beforeEach(() => TestBed.configureTestingModule({
providers: [ApiService, HttpClient]
}));
it('should be created', () => {
const service: ApiService = TestBed.inject(ApiService);
expect(service).toBeTruthy();
});
});

28
src/app/api.service.ts Normal file
View File

@ -0,0 +1,28 @@
import { Injectable } from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {LocalStorageService} from 'angular-2-local-storage';
@Injectable({
providedIn: 'root'
})
export class ApiService {
constructor(
private http: HttpClient,
private storage: LocalStorageService
) { }
get(url) {
return this.http.get(url, this.authOptions());
}
private authOptions() {
const auth = this.storage.get('basicAuth');
if (auth) {
return {headers: new HttpHeaders({Authorization: 'Basic ' + auth})};
}
else {
return {};
}
}
}

View File

@ -1,10 +1,15 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import {HomeComponent} from './home/home.component';
import {LoginService} from './login.service';
const routes: Routes = [
{path: '', component: HomeComponent}
{path: '', component: HomeComponent},
{path: 'replace-me', component: HomeComponent, canActivate: [LoginService]},
// if not authenticated
{ path: '**', redirectTo: '' }
];
@NgModule({

View File

@ -7,6 +7,8 @@ import {RbUiComponentsModule} from '@inst-iot/bosch-angular-ui-components';
import { LoginComponent } from './login/login.component';
import { HomeComponent } from './home/home.component';
import {FormsModule} from '@angular/forms';
import {LocalStorageModule} from 'angular-2-local-storage';
import {HttpClientModule} from '@angular/common/http';
@NgModule({
declarations: [
@ -15,10 +17,15 @@ import {FormsModule} from '@angular/forms';
HomeComponent
],
imports: [
LocalStorageModule.forRoot({
prefix: 'dfop',
storageType: 'localStorage'
}),
BrowserModule,
AppRoutingModule,
RbUiComponentsModule,
FormsModule
FormsModule,
HttpClientModule
],
providers: [],
bootstrap: [AppComponent]

View File

@ -0,0 +1,12 @@
import { TestBed } from '@angular/core/testing';
import { LoginService } from './login.service';
describe('LoginService', () => {
beforeEach(() => TestBed.configureTestingModule({}));
it('should be created', () => {
const service: LoginService = TestBed.inject(LoginService);
expect(service).toBeTruthy();
});
});

43
src/app/login.service.ts Normal file
View File

@ -0,0 +1,43 @@
import { Injectable } from '@angular/core';
import {ApiService} from './api.service';
import {ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot} from '@angular/router';
import {LocalStorageService} from 'angular-2-local-storage';
@Injectable({
providedIn: 'root'
})
export class LoginService implements CanActivate {
private loggedIn = false;
constructor(
private api: ApiService,
private storage: LocalStorageService
) { }
login(username, password) {
return new Promise(resolve => {
this.storage.set('basicAuth', btoa(username + ':' + password));
this.api.get('/authorized').subscribe((data: any) => {
if (data.status === 'Authorization successful') {
this.loggedIn = true;
resolve(true);
}
else {
this.loggedIn = false;
this.storage.remove('basicAuth');
resolve(false);
}
},
() => {
this.loggedIn = false;
this.storage.remove('basicAuth');
resolve(false);
});
});
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
return this.loggedIn;
}
}

View File

@ -1,10 +1,8 @@
<div class="login-wrapper">
<h2>Please log in</h2>
<rb-form-input name="username" label="username">
</rb-form-input>
<rb-form-input type="password" name="password" label="password">
</rb-form-input>
<button class="rb-btn rb-primary">Login</button>
<span>{{message}}</span>
<rb-form-input name="username" label="username" [(ngModel)]="username"></rb-form-input>
<rb-form-input type="password" name="password" label="password" [(ngModel)]="password"></rb-form-input>
<span class="message">{{message}}</span>
<button class="rb-btn rb-primary login-button" (click)="login()">Login</button>
</div>

View File

@ -1,3 +1,12 @@
.login-wrapper {
max-width: 220px;
max-width: 250px;
}
.message {
font-size: 13px;
white-space: pre-line;
}
.login-button {
display: block;
}

View File

@ -1,4 +1,6 @@
import { Component, OnInit } from '@angular/core';
import {ValidationService} from '../validation.service';
import {LoginService} from '../login.service';
@Component({
selector: 'app-login',
@ -7,13 +9,34 @@ import { Component, OnInit } from '@angular/core';
})
export class LoginComponent implements OnInit {
message = '';
message = ''; // message below login fields
username = ''; // credentials
password = '';
validCredentials = false; // true if entered credentials are valid
constructor() { }
constructor(
private validate: ValidationService,
private loginService: LoginService
) { }
ngOnInit() {
}
login() {
const {ok: userOk, error: userError} = this.validate.username(this.username);
const {ok: passwordOk, error: passwordError} = this.validate.password(this.password);
this.message = userError + (userError + passwordError === '' ? '' : '\n') + passwordError; // display errors
console.log(this.message);
if (userOk && passwordOk) {
this.loginService.login(this.username, this.password).then(ok => {
if (ok) {
this.message = 'Login successful'; // TODO: think about following action, write tests!
}
else {
this.message = 'Wrong credentials! Try again.';
}
});
}
}
}

View File

@ -6,7 +6,7 @@ describe('ValidationService', () => {
beforeEach(() => TestBed.configureTestingModule({}));
it('should be created', () => {
const service: ValidationService = TestBed.get(ValidationService);
const service: ValidationService = TestBed.inject(ValidationService);
expect(service).toBeTruthy();
});
});

View File

@ -1,9 +1,36 @@
import { Injectable } from '@angular/core';
import Joi from '@hapi/joi';
@Injectable({
providedIn: 'root'
})
export class ValidationService {
private vUsername = Joi.string()
.lowercase()
.pattern(new RegExp('^[a-z0-9-_.]+$'))
.min(1)
.max(128);
private vPassword = Joi.string()
.pattern(new RegExp('^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!"#%&\'()*+,-.\\/:;<=>?@[\\]^_`{|}~])(?=\\S+$).{8,}$'))
.max(128);
constructor() { }
username(data) {
const {ignore, error} = this.vUsername.validate(data);
if (error) {
return {ok: false, error: 'username must only contain a-z0-9-_.'};
}
return {ok: true, error: ''};
}
password(data) {
const {ignore, error} = this.vPassword.validate(data);
if (error) {
return {ok: false, error: 'password must only contain a-zA-Z0-9!"#%&\'()*+,-./:;<=>?@[]^_`{|}~'};
}
return {ok: true, error: ''};
}
}

6
src/proxy.conf.json Normal file
View File

@ -0,0 +1,6 @@
{
"/": {
"target": "http://localhost:3000",
"secure": false
}
}

View File

@ -3,6 +3,13 @@
"rules": {
"array-type": false,
"arrow-parens": false,
"brace-style": [
true,
"stroustrup",
{
"allowSingleLine": true
}
],
"deprecation": {
"severity": "warning"
},
@ -88,4 +95,4 @@
"rulesDirectory": [
"codelyzer"
]
}
}