Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import 'rxjs/add/operator/map';
- import 'rxjs/add/operator/toPromise';
- import {Injectable} from '@angular/core';
- import {UserAccountInfo} from "../../models/UserAccountInfo";
- import {CryptoService} from "../crypto/crypto";
- import {str2Uint8Array, uint8Array2Str} from "../../utils/StringUtils";
- import {PredefinedUserType} from "../../app/setup/models/InitialSetupModel";
- import {GlobalSettingsProvider} from "../global-settings/global-settings-provider";
- import {isNullOrUndefined} from "util";
- import {Storage} from "@ionic/storage"
- import {LogHandler, LogLevel} from "../../handlers/log-handler";
- import {LoggableEntity} from "../../models/interfaces/LoggableEntity";
- const USER_SECURE_STORAGE_NAME = 'fp-user-secure-storage';
- const NULL_DATA_FOR_KEY = "NULL_DATA_FOR_KEY";
- export const USER_ACCOUNT_SUFFIX = '.user.account';
- export const SAMPLE_USER_ACCOUNT_SUFFIX = '.samp.account';
- export const SAMPLE_USER_ACCOUNT_PASSWORD = 'qwer';
- /**
- * -- User --
- * Singleton provider that represents the access point of the FinancialProfile information
- */
- @Injectable()
- export class User implements LoggableEntity {
- TAG: string = User.name;
- currentUser: UserAccountInfo;
- encryptionKey; //FIXME remove
- constructor(protected storage: Storage,
- protected logger: LogHandler,
- protected cryptoService: CryptoService,
- protected globalSettingsProvider: GlobalSettingsProvider) {
- this.logger.log("Running " + this.TAG + " constructor");
- if (this.logger.level >= LogLevel.LOG) {
- this.storage.keys().then((keys) => this.logger.log('Available keys', keys));
- }
- }
- /**
- * Method used to check if the user is logged in or not
- * @returns {boolean} true if the user is logged in, false if not
- */
- public hasCurrentUser(): boolean {
- return this.currentUser != null;
- }
- /**
- * Method used to the save the current user on the persistence layer
- * @param {string} suffix optional param
- * @returns {Promise<boolean>} True/False depending on the result of the save
- */
- public saveCurrentUser(suffix: string = USER_ACCOUNT_SUFFIX): Promise<boolean> {
- this.logger.log("Saving Current User", this.currentUser.userId);
- return new Promise((resolve, reject) => {
- this.convertUserId(this.currentUser.userId).then(userId => {
- let accountKey = this.calculateAccountKey(userId, suffix);
- this.encrypt(this.currentUser, this.encryptionKey).then(encryptedAccount => {
- this.storage.get(accountKey).then((data) => {
- if (data) {
- this.storage.set(accountKey, encryptedAccount).then(() => {
- resolve(true);
- }).catch(reason => {
- this.logger.error(`Unable to save current user`, reason);
- reject(false);
- });
- }
- else {
- this.handleUnableToFindUser(NULL_DATA_FOR_KEY, reject);
- }
- }
- );
- });
- });
- });
- }
- /**
- * Uses the combination of the provided UserID and Password to login the user into the system and set maintaining the `currentUser` with that user's account information.
- * @param {string} userId username
- * @param {string} password Password provided by the user
- * @param {string} suffix optional param
- * @returns {Promise<UserAccountInfo>} Promised logged in user
- */
- public login(userId: string, password: string, suffix: string = USER_ACCOUNT_SUFFIX): Promise<UserAccountInfo> {
- this.logger.debug('Request to login user', userId);
- return new Promise((resolve, reject) => {
- this.getEncryptedUserData(userId, suffix).then((encryptedValue) => {
- this.decrypt(encryptedValue, password).then((decryptedValue) => {
- this.logger.debug('Found and loaded account info for user', userId);
- this.currentUser = decryptedValue;
- this.currentUser.isSampleProfile = (suffix != USER_ACCOUNT_SUFFIX);
- this.encryptionKey = password; //FIXME REMOVE!!
- if (!isNullOrUndefined(this.currentUser) && suffix != SAMPLE_USER_ACCOUNT_SUFFIX) {
- this.globalSettingsProvider.globalSettingsInstance.lastLoginUserId = this.currentUser.userId;
- this.globalSettingsProvider.saveToStorage();
- }
- resolve(this.currentUser);
- }).catch((reason) => {
- let error: Error = {
- message: "Unable to read user account",
- stack: reason.toString(),
- name: "unable_read_account"
- };
- this.logger.error(error.message, [error, reason]);
- reject(error);
- });
- });
- });
- }
- /**
- * Uses the combination of the provided AccountInfo and Password to create a new UserAccountInfo instance, save it on the persistence layer and login into the system.
- * @param {UserAccountInfo} accountInfo
- * @param {string} password
- * @param {string} suffix
- * @returns {Promise<UserAccountInfo>} Promised logged in user
- */
- public signup(accountInfo: UserAccountInfo, password: string, suffix: string = USER_ACCOUNT_SUFFIX): Promise<UserAccountInfo> {
- this.logger.debug('Request to signup user', accountInfo.userId);
- this.logger.log("user account info", JSON.stringify(accountInfo));
- return new Promise((resolve, reject) => {
- // Hash user
- this.convertUserId(accountInfo.userId).then((cvtUserId) => {
- // this.createSecureStorage(this.storage)
- // .then((storage) => {
- let accountKey = this.calculateAccountKey(cvtUserId, suffix);
- this.encryptionKey = password; //FIXME REMOVE!!
- this.bootstrapFinancialProfile(accountInfo);
- this.encrypt(accountInfo, password).then((encryptedAccountInfo) => {
- // Get data from secure storage -> hash_username.user.account
- this.storage.get(accountKey).then((data) => {
- if (data) {
- let error: Error = new Error("User account already exists");
- this.logger.error("Account already exists.", error);
- reject(error);
- }
- else {
- this.handleCreateUserAccount(accountKey, encryptedAccountInfo, cvtUserId, accountInfo, suffix, resolve);
- }
- }
- ).catch((reason) => {
- this.handleCreateUserAccount(accountKey, encryptedAccountInfo, cvtUserId, accountInfo, suffix, resolve);
- })
- })
- .catch((reason) => {
- let error: Error = {
- message: "Unable to encrypt account.",
- stack: reason.toString(),
- name: "unable_write_account"
- };
- this.logger.error(error.message, [error, reason]);
- reject(error);
- })
- })
- });
- }
- /**
- * Returns the list of available users
- * @param {string} filter filter to apply on the search
- * @returns {Promise<any[]>}
- */
- public async availableUsers(filter?: string): Promise<any[]> {
- let list = await this.storage.keys();
- // Filter values
- let users = this.extractUsers(list, filter);
- this.logger.log("Available users", users);
- return Promise.resolve(users);
- }
- /**
- * Log the user out, which forgets the session
- */
- public logout(): void {
- this.logger.debug("Logging current user out.");
- this.currentUser = null;
- }
- public async removeUser(userId: string) {
- let cvtUserId = await this.convertUserId(userId);
- let accountKey = await this.calculateAccountKey(cvtUserId, "");
- try {
- await this.storage.remove(accountKey);
- }
- catch (reason) {
- this.logger.debug(`Unable to remove user ${userId}`, {
- accountKey: accountKey,
- cvtUserId: cvtUserId,
- reason: reason
- })
- }
- this.logger.info(`Removed user profile ${userId}`);
- }
- /**
- * Returns the list of existing sample users
- * @returns {Promise<PredefinedUserType[]>}
- */
- public getSampleUsersList(): Promise<PredefinedUserType[]> {
- return new Promise<PredefinedUserType[]>((resolve, reject) => {
- let sampleProfiles: PredefinedUserType[] = [];
- this.availableUsers(SAMPLE_USER_ACCOUNT_SUFFIX).then(availableUsers => {
- for (let i = 0; i < availableUsers.length; i++) {
- this.getEncryptedUserData(availableUsers[i], SAMPLE_USER_ACCOUNT_SUFFIX).then(encryptedValue => {
- this.decrypt(encryptedValue, SAMPLE_USER_ACCOUNT_PASSWORD).then(userInstance => {
- let sample: PredefinedUserType = {
- userId: userInstance.userId,
- userName: userInstance.userName,
- description: userInstance.description,
- short_description: userInstance.short_description,
- photoUrl: userInstance.photoUrl
- };
- sampleProfiles.push(sample);
- // NAU21.HD: Stopping condition. Inside the loop due to promises.
- if (i == availableUsers.length - 1) {
- resolve(sampleProfiles);
- }
- });
- });
- }
- }).catch((err) => {
- reject(err);
- });
- });
- }
- /**
- * Verifies if the current user is a sample profile
- * @returns {boolean}
- */
- public isSampleProfile(): boolean {
- if (this.currentUser) {
- return this.currentUser.isSampleProfile;
- }
- return false;
- }
- /**
- * Creates the necessary objects to have a qualified financial profile
- * @param {UserAccountInfo} user
- */
- public bootstrapFinancialProfile(user: UserAccountInfo) {
- if (isNullOrUndefined(user.financialProfiles && user.financialProfiles[0])) {
- user.financialProfiles[0] = {
- calculations: {
- overview: {
- income: {},
- financialAssets: {},
- debts: {},
- expenses: {}
- }
- }
- };
- }
- }
- /**
- * Method used to get user's data from the persistence layer and return it as encrypted.
- * @param {string} userId username
- * @param {string} suffix Optinal parameter - user account's suffix to distinct from user accounts and example accounts
- * @returns {Promise<string>}
- */
- private getEncryptedUserData(userId: string, suffix: string = USER_ACCOUNT_SUFFIX): Promise<string> {
- return new Promise((resolve, reject) => {
- // Hash user
- this.convertUserId(userId).then((hashUser) => {
- this.storage.get(this.calculateAccountKey(hashUser, suffix)).then((encryptedValue) => {
- if (encryptedValue) {
- resolve(encryptedValue);
- }
- else {
- this.handleUnableToFindUser(NULL_DATA_FOR_KEY, reject);
- }
- }).catch((reason) => {
- this.handleUnableToFindUser(reason, reject);
- });
- })
- });
- }
- /**
- * Method used to handle errors related to being unable to find a user account
- * @param reason Reason to provide
- * @param reject Promise to reject
- */
- private handleUnableToFindUser(reason, reject) {
- let error: Error = {
- message: "unable to find user account",
- stack: reason.toString(),
- name: "no_account_found"
- };
- this.logger.error(error.message, [error, reason]);
- reject(error);
- }
- /**
- * Method used to handle the creation of the user account
- * @param {string} accountKey
- * @param encryptedAccountInfo
- * @param cvtUserId
- * @param {UserAccountInfo} accountInfo
- * @param {string} suffix
- * @param resolve
- */
- private handleCreateUserAccount(accountKey: string, encryptedAccountInfo, cvtUserId, accountInfo: UserAccountInfo, suffix: string, resolve) {
- this.storage.set(accountKey, encryptedAccountInfo).then(() => {
- this.logger.debug('Create account info for user', cvtUserId);
- this.currentUser = accountInfo;
- this.currentUser.isSampleProfile = (suffix != USER_ACCOUNT_SUFFIX);
- resolve(this.currentUser);
- });
- }
- /**
- * Calculates the user account's key
- * @param {string} hashUser
- * @param {string} suffix
- * @returns {string}
- */
- private calculateAccountKey(hashUser: string, suffix: string): string {
- return hashUser + suffix;
- }
- private convertUserId(userId: string): Promise<string> {
- // this.log.debug("Hashing user name");
- // return this.cryptoService.hashSHAString(userId).then(
- // (hashedUserId) => uint8Array2Str(hashedUserId)
- // );
- return Promise.resolve(userId);
- }
- private async encrypt(accountInfo: UserAccountInfo, password: string): Promise<string> {
- this.logger.debug("Encrypting information");
- let cryptoKey = await this.cryptoService.generateKeyFromPassword(password);
- let data = str2Uint8Array(JSON.stringify(accountInfo));
- let encryptedContent = await this.cryptoService.encrypt(data.buffer, cryptoKey);
- return Promise.resolve(uint8Array2Str(encryptedContent));
- }
- private async decrypt(encryptedValue: string, password: string): Promise<UserAccountInfo> {
- this.logger.debug("Decrypting content");
- let uint8Array = str2Uint8Array(encryptedValue);
- let cryptoKey = await this.cryptoService.generateKeyFromPassword(password);
- let decryptedData = await this.cryptoService.decrypt(uint8Array.buffer, cryptoKey);
- let s = uint8Array2Str(decryptedData);
- return Promise.resolve(JSON.parse(s));
- }
- private extractUsers(list: string[], filter?: string) {
- let users = [];
- for (let item of list) {
- if (filter) {
- if (item.indexOf(filter) > 0) {
- users.push(this.getReadableUsername(item, filter));
- }
- } else {
- if (item.endsWith(USER_ACCOUNT_SUFFIX) && !(item.indexOf(SAMPLE_USER_ACCOUNT_SUFFIX) > 0)) {
- users.push(this.getReadableUsername(item, SAMPLE_USER_ACCOUNT_SUFFIX));
- }
- }
- }
- users = users.sort();
- return users;
- }
- private getReadableUsername(item: string, suffix: string): string {
- return item.substring(0, item.length - suffix.length);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement