Skip to content

Commit

Permalink
Fix secure storage on browser platform (fix alastria#76)
Browse files Browse the repository at this point in the history
  • Loading branch information
Rafael Barriuso committed Oct 19, 2020
1 parent 6223b5f commit 8a18c62
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 96 deletions.
4 changes: 2 additions & 2 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { BrowserModule } from '@angular/platform-browser';
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { BarcodeScanner } from '@ionic-native/barcode-scanner/ngx';
import { NgxQRCodeModule } from 'ngx-qrcode2';
import { SecureStorage } from '@ionic-native/secure-storage/ngx';
import { SecureStorageEcho } from '@ionic-native/secure-storage-echo/ngx';
import { HttpClientModule } from '@angular/common/http';
import { Deeplinks } from '@ionic-native/deeplinks/ngx';
import { AppComponent } from './app.component';
Expand Down Expand Up @@ -63,7 +63,7 @@ import { AuthenticationService } from './services/authentication.service';
providers: [
BarcodeScanner,
Deeplinks,
SecureStorage,
SecureStorageEcho,
Web3Service,
SplashScreen,
StatusBar,
Expand Down
168 changes: 83 additions & 85 deletions src/app/pages/login/login.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AuthenticationService } from './../../services/authentication.service';
import { Component, Output, EventEmitter } from '@angular/core';
import { Component } from '@angular/core';
import { Platform } from '@ionic/angular';
import { FingerprintAIO } from '@ionic-native/fingerprint-aio/ngx';

Expand All @@ -8,7 +8,7 @@ import { FingerprintAIO } from '@ionic-native/fingerprint-aio/ngx';
import { SecuredStorageService } from '../../services/securedStorage.service';
import { Validators, FormBuilder, FormGroup } from '@angular/forms';
import { Deeplinks } from '@ionic-native/deeplinks/ngx';
import { ActivatedRoute, Router, NavigationExtras } from '@angular/router';
import { Router, NavigationExtras } from '@angular/router';
import { parseCredentials } from 'src/utils';

/**
Expand Down Expand Up @@ -51,66 +51,16 @@ export class LoginPage {
];
hashKeyLoginType: boolean;

constructor(private platform: Platform,
private faio: FingerprintAIO,
constructor(private faio: FingerprintAIO,
private securedStrg: SecuredStorageService,
private authenticationService: AuthenticationService,
private fb: FormBuilder,
private router: Router,
private route: ActivatedRoute,
private deeplinks: Deeplinks) {
this.platform.backButton.subscribe(() => {
if (this.loginType) {
if (!this.hashKeyLoginType) {
this.loginType = null;
}
}
});
private deeplinks: Deeplinks,
platform: Platform) {

this.platform.ready()
.then(async () => {
await this.securedStrg.initSecureStorage();
await this.securedStrg.set('isLogged', 'false');
this.hashKeyLoginType = await this.securedStrg.hasKey('loginType');
this.initPlatform(platform).then(() => console.log("Platform initialized"))

if (this.hashKeyLoginType) {
const loginTypeRes = await this.securedStrg.getLoginType();
this.selectTypeLogin(loginTypeRes);
} else {
this.faio.isAvailable()
.then( (res) => {
if (res === 'OK') {
this.buttons.push(
{
type: 'fingerprint',
label: 'ACCEDE CON HUELLA'
}
);
} else {
this.selectTypeLogin(this.buttons[0].type);
}
})
.catch(() => {
this.selectTypeLogin(this.buttons[0].type);
});
}
this.deeplinks.route({
'/': LoginPage,
'/login': LoginPage,
'/createAI': LoginPage,
'/createCredentials': LoginPage,
'/createPresentations': LoginPage
}).subscribe(
async (match) => {
const path = (match && match.$link) ? match.$link.path : null;
const isLogged = await this.securedStrg.get('isLogged');
this.isLogged = (isLogged) ? JSON.parse(isLogged) : false;
this.controlDeeplink(path, match.$args);
},
(noMatch) => {
}
);
});
}

selectTypeLogin(type: string) {
Expand Down Expand Up @@ -141,13 +91,15 @@ export class LoginPage {
this.accessKeyForm.get('key').setErrors({incorrect: true});
}
this.handleLogin(isAuthorized);
} else {
console.log("Invalid access key form");
}
}

/*
* Generate accessKeyForm with inputsForm
*/
generateForm(): void {
private generateForm(): void {
if (this.hashKeyLoginType) {
this.inputsKeyForm.splice(1, 1);
this.accessKeyForm = this.fb.group({
Expand Down Expand Up @@ -182,39 +134,31 @@ export class LoginPage {
}

regFinger() {
return new Promise(
(next, reject) => {
this.faio.isAvailable()
.then(result => {
this.faio.show({
//clientId: 'AlastriaID',
//clientSecret: 'NddAHBODmhACXHITWJTU',
disableBackup: true,
//localizedFallbackTitle: 'Touch ID for AlastriaID', // Only for iOS
})
return this.faio.isAvailable()
.then(result => {
this.faio.show({
//clientId: 'AlastriaID',
//clientSecret: 'NddAHBODmhACXHITWJTU',
disableBackup: true,
//localizedFallbackTitle: 'Touch ID for AlastriaID', // Only for iOS
})
.then(() => {
this.securedStrg.setLoginType(this.loginType)
.then(() => {
this.securedStrg.setLoginType(this.loginType)
.then(() => {
this.handleLogin(true);
});
})
.catch(() => {
this.handleLogin(false);
reject('Error in fingerprint');
this.handleLogin(true);
});
}).catch(err => {
})
.catch(() => {
this.handleLogin(false);
if (err === 'cordova_not_available') {
reject('Cordova not aviable');
} else {
reject(err);
}
throw 'Error in fingerprint';
});
}
);
}).catch(err => {
this.handleLogin(false);
throw err === 'cordova_not_available' ? 'Cordova not available' : err;
});
}

async handleLogin(isLogged: boolean): Promise<any> {
private async handleLogin(isLogged: boolean): Promise<any> {
this.isLogged = isLogged;
await this.securedStrg.set('isLogged', this.isLogged.toString());
if (isLogged) {
Expand Down Expand Up @@ -264,10 +208,64 @@ export class LoginPage {
break;

default:

console.log("WARNING: unsupported deep link: " + path);
break;
}
}

private async initPlatform(platform: Platform): Promise<void> {
await platform.ready();
console.log("Platform ready. Starting initialization...")
try{
await this.securedStrg.initSecureStorage();
await this.securedStrg.set('isLogged', 'false');
this.hashKeyLoginType = await this.securedStrg.hasKey('loginType');
}catch(err){
console.log("Secure storage initialization error", err);
}
if (this.hashKeyLoginType) {
const loginTypeRes = await this.securedStrg.getLoginType();
this.selectTypeLogin(loginTypeRes);
} else {
console.log("Checking fingerprint");
const fioAvailable = await this.faio.isAvailable().catch(() => 'KO');
if(fioAvailable === 'OK') {
this.buttons.push(
{
type: 'fingerprint',
label: 'ACCEDE CON HUELLA'
}
);
} else {
console.log("WARNING: Fingerprint not available");
this.selectTypeLogin(this.buttons[0].type);
}
}
this.deeplinks.route({
'/': LoginPage,
'/login': LoginPage,
'/createAI': LoginPage,
'/createCredentials': LoginPage,
'/createPresentations': LoginPage
}).subscribe(
async (match) => {
const path = (match && match.$link) ? match.$link.path : null;
const isLogged = await this.securedStrg.get('isLogged');
this.isLogged = (isLogged) ? JSON.parse(isLogged) : false;
this.controlDeeplink(path, match.$args);
},
(noMatch) => {
}
);

platform.backButton.subscribe(() => {
if (this.loginType) {
if (!this.hashKeyLoginType) {
this.loginType = null;
}
}
});

}

}
61 changes: 52 additions & 9 deletions src/app/services/securedStorage.service.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,69 @@
import { Injectable } from '@angular/core';
import { SecureStorage, SecureStorageObject } from '@ionic-native/secure-storage/ngx';
import { SecureStorageEcho, SecureStorageEchoObject } from '@ionic-native/secure-storage-echo/ngx';

import { AppConfig } from '../../app.config';

class LocalStorageWrapper {

private readonly PREFIX = '__SS__';

get(key: string): Promise<string> {
return Promise.resolve(localStorage.getItem(this.PREFIX + key));
}

set(key: string, value: string): Promise<any> {
return Promise.resolve(localStorage.setItem(this.PREFIX + key, value));
}

remove(key: string): Promise<string> {
localStorage.removeItem(this.PREFIX + key);
return Promise.resolve(key);
}

keys(): Promise<string[]> {
const ret = new Array<string>();
for(let i = 0; i < localStorage.length; ++i) {
ret.push(localStorage.key(i));
}
return Promise.resolve(ret.filter(key => key && key.indexOf(this.PREFIX) === 0));
}

clear(): Promise<any> {
for(let i = 0; i < localStorage.length; ++i) {
const key = localStorage.key(i);
if(key && key.indexOf(this.PREFIX) === 0) {
localStorage.removeItem(key);
}
}
return Promise.resolve();
}

secureDevice(): Promise<any> {
return Promise.resolve();
}

}

@Injectable({
providedIn: 'root',
})
export class SecuredStorageService {

securedStorageObject: SecureStorageObject;
promiseState: Promise<any>;
private securedStorageObject: SecureStorageEchoObject;

constructor(
private securedStorage: SecureStorage
private securedStorage: SecureStorageEcho
) {
}

initSecureStorage(): Promise<void> {
return this.securedStorage.create('identitySecureStorage').then(
(securedStorageObject) => {
this.securedStorageObject = securedStorageObject;
}
);
return (this.securedStorage.create('identitySecureStorage') || Promise.reject("No plugin"))
.then(ssObj => {
this.securedStorageObject = ssObj;
}).catch(err => {
console.log('WARNING: Secure storage not available, falling back to localStorage. Err: ', err);
this.securedStorageObject = new LocalStorageWrapper() as unknown as SecureStorageEchoObject;
});
}

// GETTERS
Expand Down

0 comments on commit 8a18c62

Please sign in to comment.