before update
This commit is contained in:
parent
7f47af425d
commit
7cc6147a25
@ -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
2869
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -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",
|
||||
|
14
src/app/api.service.spec.ts
Normal file
14
src/app/api.service.spec.ts
Normal 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
28
src/app/api.service.ts
Normal 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 {};
|
||||
}
|
||||
}
|
||||
}
|
@ -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({
|
||||
|
@ -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]
|
||||
|
12
src/app/login.service.spec.ts
Normal file
12
src/app/login.service.spec.ts
Normal 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
43
src/app/login.service.ts
Normal 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;
|
||||
}
|
||||
}
|
@ -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>
|
||||
|
@ -1,3 +1,12 @@
|
||||
.login-wrapper {
|
||||
max-width: 220px;
|
||||
max-width: 250px;
|
||||
}
|
||||
|
||||
.message {
|
||||
font-size: 13px;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
.login-button {
|
||||
display: block;
|
||||
}
|
||||
|
@ -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.';
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
@ -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
6
src/proxy.conf.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"/": {
|
||||
"target": "http://localhost:3000",
|
||||
"secure": false
|
||||
}
|
||||
}
|
@ -3,6 +3,13 @@
|
||||
"rules": {
|
||||
"array-type": false,
|
||||
"arrow-parens": false,
|
||||
"brace-style": [
|
||||
true,
|
||||
"stroustrup",
|
||||
{
|
||||
"allowSingleLine": true
|
||||
}
|
||||
],
|
||||
"deprecation": {
|
||||
"severity": "warning"
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user