support for prelogin kdf info
This commit is contained in:
parent
a7bbdf9c93
commit
9f26f9f377
|
@ -27,6 +27,7 @@ import { PasswordHintRequest } from '../models/request/passwordHintRequest';
|
||||||
import { PasswordRequest } from '../models/request/passwordRequest';
|
import { PasswordRequest } from '../models/request/passwordRequest';
|
||||||
import { PasswordVerificationRequest } from '../models/request/passwordVerificationRequest';
|
import { PasswordVerificationRequest } from '../models/request/passwordVerificationRequest';
|
||||||
import { PaymentRequest } from '../models/request/paymentRequest';
|
import { PaymentRequest } from '../models/request/paymentRequest';
|
||||||
|
import { PreloginRequest } from '../models/request/preloginRequest';
|
||||||
import { RegisterRequest } from '../models/request/registerRequest';
|
import { RegisterRequest } from '../models/request/registerRequest';
|
||||||
import { SeatRequest } from '../models/request/seatRequest';
|
import { SeatRequest } from '../models/request/seatRequest';
|
||||||
import { StorageRequest } from '../models/request/storageRequest';
|
import { StorageRequest } from '../models/request/storageRequest';
|
||||||
|
@ -70,6 +71,7 @@ import {
|
||||||
OrganizationUserDetailsResponse,
|
OrganizationUserDetailsResponse,
|
||||||
OrganizationUserUserDetailsResponse,
|
OrganizationUserUserDetailsResponse,
|
||||||
} from '../models/response/organizationUserResponse';
|
} from '../models/response/organizationUserResponse';
|
||||||
|
import { PreloginResponse } from '../models/response/preloginResponse';
|
||||||
import { ProfileResponse } from '../models/response/profileResponse';
|
import { ProfileResponse } from '../models/response/profileResponse';
|
||||||
import { SyncResponse } from '../models/response/syncResponse';
|
import { SyncResponse } from '../models/response/syncResponse';
|
||||||
import { TwoFactorAuthenticatorResponse } from '../models/response/twoFactorAuthenticatorResponse';
|
import { TwoFactorAuthenticatorResponse } from '../models/response/twoFactorAuthenticatorResponse';
|
||||||
|
@ -93,6 +95,7 @@ export abstract class ApiService {
|
||||||
getProfile: () => Promise<ProfileResponse>;
|
getProfile: () => Promise<ProfileResponse>;
|
||||||
getUserBilling: () => Promise<BillingResponse>;
|
getUserBilling: () => Promise<BillingResponse>;
|
||||||
putProfile: (request: UpdateProfileRequest) => Promise<ProfileResponse>;
|
putProfile: (request: UpdateProfileRequest) => Promise<ProfileResponse>;
|
||||||
|
postPrelogin: (request: PreloginRequest) => Promise<PreloginResponse>;
|
||||||
postEmailToken: (request: EmailTokenRequest) => Promise<any>;
|
postEmailToken: (request: EmailTokenRequest) => Promise<any>;
|
||||||
postEmail: (request: EmailRequest) => Promise<any>;
|
postEmail: (request: EmailRequest) => Promise<any>;
|
||||||
postPassword: (request: PasswordRequest) => Promise<any>;
|
postPassword: (request: PasswordRequest) => Promise<any>;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { TwoFactorProviderType } from '../enums/twoFactorProviderType';
|
import { TwoFactorProviderType } from '../enums/twoFactorProviderType';
|
||||||
|
|
||||||
import { AuthResult } from '../models/domain/authResult';
|
import { AuthResult } from '../models/domain/authResult';
|
||||||
|
import { SymmetricCryptoKey } from '../models/domain/symmetricCryptoKey';
|
||||||
|
|
||||||
export abstract class AuthService {
|
export abstract class AuthService {
|
||||||
email: string;
|
email: string;
|
||||||
|
@ -16,4 +17,5 @@ export abstract class AuthService {
|
||||||
logOut: (callback: Function) => void;
|
logOut: (callback: Function) => void;
|
||||||
getSupportedTwoFactorProviders: (win: Window) => any[];
|
getSupportedTwoFactorProviders: (win: Window) => any[];
|
||||||
getDefaultTwoFactorProvider: (u2fSupported: boolean) => TwoFactorProviderType;
|
getDefaultTwoFactorProvider: (u2fSupported: boolean) => TwoFactorProviderType;
|
||||||
|
makePreloginKey: (masterPassword: string, email: string) => Promise<SymmetricCryptoKey>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ import { SymmetricCryptoKey } from '../models/domain/symmetricCryptoKey';
|
||||||
|
|
||||||
import { ProfileOrganizationResponse } from '../models/response/profileOrganizationResponse';
|
import { ProfileOrganizationResponse } from '../models/response/profileOrganizationResponse';
|
||||||
|
|
||||||
|
import { KdfType } from '../enums/kdfType';
|
||||||
|
|
||||||
export abstract class CryptoService {
|
export abstract class CryptoService {
|
||||||
setKey: (key: SymmetricCryptoKey) => Promise<any>;
|
setKey: (key: SymmetricCryptoKey) => Promise<any>;
|
||||||
setKeyHash: (keyHash: string) => Promise<{}>;
|
setKeyHash: (keyHash: string) => Promise<{}>;
|
||||||
|
@ -25,7 +27,7 @@ export abstract class CryptoService {
|
||||||
clearOrgKeys: (memoryOnly?: boolean) => Promise<any>;
|
clearOrgKeys: (memoryOnly?: boolean) => Promise<any>;
|
||||||
clearKeys: () => Promise<any>;
|
clearKeys: () => Promise<any>;
|
||||||
toggleKey: () => Promise<any>;
|
toggleKey: () => Promise<any>;
|
||||||
makeKey: (password: string, salt: string) => Promise<SymmetricCryptoKey>;
|
makeKey: (password: string, salt: string, kdf: KdfType, kdfIterations: number) => Promise<SymmetricCryptoKey>;
|
||||||
makeShareKey: () => Promise<[CipherString, SymmetricCryptoKey]>;
|
makeShareKey: () => Promise<[CipherString, SymmetricCryptoKey]>;
|
||||||
makeKeyPair: (key?: SymmetricCryptoKey) => Promise<[string, CipherString]>;
|
makeKeyPair: (key?: SymmetricCryptoKey) => Promise<[string, CipherString]>;
|
||||||
hashPassword: (password: string, key: SymmetricCryptoKey) => Promise<string>;
|
hashPassword: (password: string, key: SymmetricCryptoKey) => Promise<string>;
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import { OrganizationData } from '../models/data/organizationData';
|
import { OrganizationData } from '../models/data/organizationData';
|
||||||
import { Organization } from '../models/domain/organization';
|
import { Organization } from '../models/domain/organization';
|
||||||
|
|
||||||
export abstract class UserService {
|
import { KdfType } from '../enums/kdfType';
|
||||||
userId: string;
|
|
||||||
email: string;
|
|
||||||
stamp: string;
|
|
||||||
|
|
||||||
setUserIdAndEmail: (userId: string, email: string) => Promise<any>;
|
export abstract class UserService {
|
||||||
|
setInformation: (userId: string, email: string, kdf: KdfType, kdfIterations: number) => Promise<any>;
|
||||||
setSecurityStamp: (stamp: string) => Promise<any>;
|
setSecurityStamp: (stamp: string) => Promise<any>;
|
||||||
getUserId: () => Promise<string>;
|
getUserId: () => Promise<string>;
|
||||||
getEmail: () => Promise<string>;
|
getEmail: () => Promise<string>;
|
||||||
getSecurityStamp: () => Promise<string>;
|
getSecurityStamp: () => Promise<string>;
|
||||||
|
getKdf: () => Promise<KdfType>;
|
||||||
|
getKdfIterations: () => Promise<number>;
|
||||||
clear: () => Promise<any>;
|
clear: () => Promise<any>;
|
||||||
isAuthenticated: () => Promise<boolean>;
|
isAuthenticated: () => Promise<boolean>;
|
||||||
getOrganization: (id: string) => Promise<Organization>;
|
getOrganization: (id: string) => Promise<Organization>;
|
||||||
|
|
|
@ -10,7 +10,6 @@ import { CryptoService } from '../../abstractions/crypto.service';
|
||||||
import { ExportService } from '../../abstractions/export.service';
|
import { ExportService } from '../../abstractions/export.service';
|
||||||
import { I18nService } from '../../abstractions/i18n.service';
|
import { I18nService } from '../../abstractions/i18n.service';
|
||||||
import { PlatformUtilsService } from '../../abstractions/platformUtils.service';
|
import { PlatformUtilsService } from '../../abstractions/platformUtils.service';
|
||||||
import { UserService } from '../../abstractions/user.service';
|
|
||||||
|
|
||||||
export class ExportComponent {
|
export class ExportComponent {
|
||||||
@Output() onSaved = new EventEmitter();
|
@Output() onSaved = new EventEmitter();
|
||||||
|
@ -20,9 +19,9 @@ export class ExportComponent {
|
||||||
showPassword = false;
|
showPassword = false;
|
||||||
|
|
||||||
constructor(protected analytics: Angulartics2, protected toasterService: ToasterService,
|
constructor(protected analytics: Angulartics2, protected toasterService: ToasterService,
|
||||||
protected cryptoService: CryptoService, protected userService: UserService,
|
protected cryptoService: CryptoService, protected i18nService: I18nService,
|
||||||
protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService,
|
protected platformUtilsService: PlatformUtilsService, protected exportService: ExportService,
|
||||||
protected exportService: ExportService, protected win: Window) { }
|
protected win: Window) { }
|
||||||
|
|
||||||
async submit() {
|
async submit() {
|
||||||
if (this.masterPassword == null || this.masterPassword === '') {
|
if (this.masterPassword == null || this.masterPassword === '') {
|
||||||
|
@ -31,11 +30,8 @@ export class ExportComponent {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const email = await this.userService.getEmail();
|
const keyHash = await this.cryptoService.hashPassword(this.masterPassword, null);
|
||||||
const key = await this.cryptoService.makeKey(this.masterPassword, email);
|
|
||||||
const keyHash = await this.cryptoService.hashPassword(this.masterPassword, key);
|
|
||||||
const storedKeyHash = await this.cryptoService.getKeyHash();
|
const storedKeyHash = await this.cryptoService.getKeyHash();
|
||||||
|
|
||||||
if (storedKeyHash != null && keyHash != null && storedKeyHash === keyHash) {
|
if (storedKeyHash != null && keyHash != null && storedKeyHash === keyHash) {
|
||||||
try {
|
try {
|
||||||
this.formPromise = this.getExportData();
|
this.formPromise = this.getExportData();
|
||||||
|
|
|
@ -28,7 +28,9 @@ export class LockComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
const email = await this.userService.getEmail();
|
const email = await this.userService.getEmail();
|
||||||
const key = await this.cryptoService.makeKey(this.masterPassword, email);
|
const kdf = await this.userService.getKdf();
|
||||||
|
const kdfIterations = await this.userService.getKdfIterations();
|
||||||
|
const key = await this.cryptoService.makeKey(this.masterPassword, email, kdf, kdfIterations);
|
||||||
const keyHash = await this.cryptoService.hashPassword(this.masterPassword, key);
|
const keyHash = await this.cryptoService.hashPassword(this.masterPassword, key);
|
||||||
const storedKeyHash = await this.cryptoService.getKeyHash();
|
const storedKeyHash = await this.cryptoService.getKeyHash();
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,8 @@ import { CryptoService } from '../../abstractions/crypto.service';
|
||||||
import { I18nService } from '../../abstractions/i18n.service';
|
import { I18nService } from '../../abstractions/i18n.service';
|
||||||
import { StateService } from '../../abstractions/state.service';
|
import { StateService } from '../../abstractions/state.service';
|
||||||
|
|
||||||
|
import { KdfType } from '../../enums/kdfType';
|
||||||
|
|
||||||
export class RegisterComponent {
|
export class RegisterComponent {
|
||||||
name: string = '';
|
name: string = '';
|
||||||
email: string = '';
|
email: string = '';
|
||||||
|
@ -57,12 +59,14 @@ export class RegisterComponent {
|
||||||
|
|
||||||
this.name = this.name === '' ? null : this.name;
|
this.name = this.name === '' ? null : this.name;
|
||||||
this.email = this.email.toLowerCase();
|
this.email = this.email.toLowerCase();
|
||||||
const key = await this.cryptoService.makeKey(this.masterPassword, this.email);
|
const kdf = KdfType.PBKDF2;
|
||||||
|
const kdfIterations = 5000;
|
||||||
|
const key = await this.cryptoService.makeKey(this.masterPassword, this.email, kdf, kdfIterations);
|
||||||
const encKey = await this.cryptoService.makeEncKey(key);
|
const encKey = await this.cryptoService.makeEncKey(key);
|
||||||
const hashedPassword = await this.cryptoService.hashPassword(this.masterPassword, key);
|
const hashedPassword = await this.cryptoService.hashPassword(this.masterPassword, key);
|
||||||
const keys = await this.cryptoService.makeKeyPair(encKey[0]);
|
const keys = await this.cryptoService.makeKeyPair(encKey[0]);
|
||||||
const request = new RegisterRequest(this.email, this.name, hashedPassword,
|
const request = new RegisterRequest(this.email, this.name, hashedPassword,
|
||||||
this.hint, encKey[1].encryptedString);
|
this.hint, encKey[1].encryptedString, kdf, kdfIterations);
|
||||||
request.keys = new KeysRequest(keys[0], keys[1].encryptedString);
|
request.keys = new KeysRequest(keys[0], keys[1].encryptedString);
|
||||||
const orgInvite = await this.stateService.get<any>('orgInvitation');
|
const orgInvite = await this.stateService.get<any>('orgInvitation');
|
||||||
if (orgInvite != null && orgInvite.token != null && orgInvite.organizationUserId != null) {
|
if (orgInvite != null && orgInvite.token != null && orgInvite.organizationUserId != null) {
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
export enum KdfType {
|
||||||
|
PBKDF2 = 0,
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
export class PreloginRequest {
|
||||||
|
email: string;
|
||||||
|
|
||||||
|
constructor(email: string) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
import { KeysRequest } from './keysRequest';
|
import { KeysRequest } from './keysRequest';
|
||||||
|
|
||||||
|
import { KdfType } from '../../enums/kdfType';
|
||||||
|
|
||||||
export class RegisterRequest {
|
export class RegisterRequest {
|
||||||
name: string;
|
name: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
@ -9,12 +11,17 @@ export class RegisterRequest {
|
||||||
keys: KeysRequest;
|
keys: KeysRequest;
|
||||||
token: string;
|
token: string;
|
||||||
organizationUserId: string;
|
organizationUserId: string;
|
||||||
|
kdf: KdfType;
|
||||||
|
kdfIterations: number;
|
||||||
|
|
||||||
constructor(email: string, name: string, masterPasswordHash: string, masterPasswordHint: string, key: string) {
|
constructor(email: string, name: string, masterPasswordHash: string, masterPasswordHint: string, key: string,
|
||||||
|
kdf: KdfType, kdfIterations: number) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.email = email;
|
this.email = email;
|
||||||
this.masterPasswordHash = masterPasswordHash;
|
this.masterPasswordHash = masterPasswordHash;
|
||||||
this.masterPasswordHint = masterPasswordHint ? masterPasswordHint : null;
|
this.masterPasswordHint = masterPasswordHint ? masterPasswordHint : null;
|
||||||
this.key = key;
|
this.key = key;
|
||||||
|
this.kdf = kdf;
|
||||||
|
this.kdfIterations = kdfIterations;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { KdfType } from '../../enums/kdfType';
|
||||||
|
|
||||||
|
export class PreloginResponse {
|
||||||
|
kdf: KdfType;
|
||||||
|
kdfIterations: number;
|
||||||
|
|
||||||
|
constructor(response: any) {
|
||||||
|
this.kdf = response.Kdf;
|
||||||
|
this.kdfIterations = response.KdfIterations;
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,6 +33,7 @@ import { PasswordHintRequest } from '../models/request/passwordHintRequest';
|
||||||
import { PasswordRequest } from '../models/request/passwordRequest';
|
import { PasswordRequest } from '../models/request/passwordRequest';
|
||||||
import { PasswordVerificationRequest } from '../models/request/passwordVerificationRequest';
|
import { PasswordVerificationRequest } from '../models/request/passwordVerificationRequest';
|
||||||
import { PaymentRequest } from '../models/request/paymentRequest';
|
import { PaymentRequest } from '../models/request/paymentRequest';
|
||||||
|
import { PreloginRequest } from '../models/request/preloginRequest';
|
||||||
import { RegisterRequest } from '../models/request/registerRequest';
|
import { RegisterRequest } from '../models/request/registerRequest';
|
||||||
import { SeatRequest } from '../models/request/seatRequest';
|
import { SeatRequest } from '../models/request/seatRequest';
|
||||||
import { StorageRequest } from '../models/request/storageRequest';
|
import { StorageRequest } from '../models/request/storageRequest';
|
||||||
|
@ -77,6 +78,7 @@ import {
|
||||||
OrganizationUserDetailsResponse,
|
OrganizationUserDetailsResponse,
|
||||||
OrganizationUserUserDetailsResponse,
|
OrganizationUserUserDetailsResponse,
|
||||||
} from '../models/response/organizationUserResponse';
|
} from '../models/response/organizationUserResponse';
|
||||||
|
import { PreloginResponse } from '../models/response/preloginResponse';
|
||||||
import { ProfileResponse } from '../models/response/profileResponse';
|
import { ProfileResponse } from '../models/response/profileResponse';
|
||||||
import { SyncResponse } from '../models/response/syncResponse';
|
import { SyncResponse } from '../models/response/syncResponse';
|
||||||
import { TwoFactorAuthenticatorResponse } from '../models/response/twoFactorAuthenticatorResponse';
|
import { TwoFactorAuthenticatorResponse } from '../models/response/twoFactorAuthenticatorResponse';
|
||||||
|
@ -196,6 +198,11 @@ export class ApiService implements ApiServiceAbstraction {
|
||||||
return new ProfileResponse(r);
|
return new ProfileResponse(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async postPrelogin(request: PreloginRequest): Promise<PreloginResponse> {
|
||||||
|
const r = await this.send('POST', '/accounts/prelogin', request, false, true);
|
||||||
|
return new PreloginResponse(r);
|
||||||
|
}
|
||||||
|
|
||||||
postEmailToken(request: EmailTokenRequest): Promise<any> {
|
postEmailToken(request: EmailTokenRequest): Promise<any> {
|
||||||
return this.send('POST', '/accounts/email-token', request, true, false);
|
return this.send('POST', '/accounts/email-token', request, true, false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { KdfType } from '../enums/kdfType';
|
||||||
import { TwoFactorProviderType } from '../enums/twoFactorProviderType';
|
import { TwoFactorProviderType } from '../enums/twoFactorProviderType';
|
||||||
|
|
||||||
import { AuthResult } from '../models/domain/authResult';
|
import { AuthResult } from '../models/domain/authResult';
|
||||||
|
@ -5,8 +6,10 @@ import { SymmetricCryptoKey } from '../models/domain/symmetricCryptoKey';
|
||||||
|
|
||||||
import { DeviceRequest } from '../models/request/deviceRequest';
|
import { DeviceRequest } from '../models/request/deviceRequest';
|
||||||
import { KeysRequest } from '../models/request/keysRequest';
|
import { KeysRequest } from '../models/request/keysRequest';
|
||||||
|
import { PreloginRequest } from '../models/request/preloginRequest';
|
||||||
import { TokenRequest } from '../models/request/tokenRequest';
|
import { TokenRequest } from '../models/request/tokenRequest';
|
||||||
|
|
||||||
|
import { ErrorResponse } from '../models/response/errorResponse';
|
||||||
import { IdentityTokenResponse } from '../models/response/identityTokenResponse';
|
import { IdentityTokenResponse } from '../models/response/identityTokenResponse';
|
||||||
import { IdentityTwoFactorResponse } from '../models/response/identityTwoFactorResponse';
|
import { IdentityTwoFactorResponse } from '../models/response/identityTwoFactorResponse';
|
||||||
|
|
||||||
|
@ -77,6 +80,8 @@ export class AuthService {
|
||||||
selectedTwoFactorProviderType: TwoFactorProviderType = null;
|
selectedTwoFactorProviderType: TwoFactorProviderType = null;
|
||||||
|
|
||||||
private key: SymmetricCryptoKey;
|
private key: SymmetricCryptoKey;
|
||||||
|
private kdf: KdfType;
|
||||||
|
private kdfIterations: number;
|
||||||
|
|
||||||
constructor(private cryptoService: CryptoService, private apiService: ApiService,
|
constructor(private cryptoService: CryptoService, private apiService: ApiService,
|
||||||
private userService: UserService, private tokenService: TokenService,
|
private userService: UserService, private tokenService: TokenService,
|
||||||
|
@ -108,8 +113,7 @@ export class AuthService {
|
||||||
|
|
||||||
async logIn(email: string, masterPassword: string): Promise<AuthResult> {
|
async logIn(email: string, masterPassword: string): Promise<AuthResult> {
|
||||||
this.selectedTwoFactorProviderType = null;
|
this.selectedTwoFactorProviderType = null;
|
||||||
email = email.toLowerCase();
|
const key = await this.makePreloginKey(masterPassword, email);
|
||||||
const key = await this.cryptoService.makeKey(masterPassword, email);
|
|
||||||
const hashedPassword = await this.cryptoService.hashPassword(masterPassword, key);
|
const hashedPassword = await this.cryptoService.hashPassword(masterPassword, key);
|
||||||
return await this.logInHelper(email, hashedPassword, key);
|
return await this.logInHelper(email, hashedPassword, key);
|
||||||
}
|
}
|
||||||
|
@ -123,8 +127,7 @@ export class AuthService {
|
||||||
async logInComplete(email: string, masterPassword: string, twoFactorProvider: TwoFactorProviderType,
|
async logInComplete(email: string, masterPassword: string, twoFactorProvider: TwoFactorProviderType,
|
||||||
twoFactorToken: string, remember?: boolean): Promise<AuthResult> {
|
twoFactorToken: string, remember?: boolean): Promise<AuthResult> {
|
||||||
this.selectedTwoFactorProviderType = null;
|
this.selectedTwoFactorProviderType = null;
|
||||||
email = email.toLowerCase();
|
const key = await this.makePreloginKey(masterPassword, email);
|
||||||
const key = await this.cryptoService.makeKey(masterPassword, email);
|
|
||||||
const hashedPassword = await this.cryptoService.hashPassword(masterPassword, key);
|
const hashedPassword = await this.cryptoService.hashPassword(masterPassword, key);
|
||||||
return await this.logInHelper(email, hashedPassword, key, twoFactorProvider, twoFactorToken, remember);
|
return await this.logInHelper(email, hashedPassword, key, twoFactorProvider, twoFactorToken, remember);
|
||||||
}
|
}
|
||||||
|
@ -195,6 +198,24 @@ export class AuthService {
|
||||||
return providerType;
|
return providerType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async makePreloginKey(masterPassword: string, email: string): Promise<SymmetricCryptoKey> {
|
||||||
|
email = email.toLowerCase();
|
||||||
|
this.kdf = null;
|
||||||
|
this.kdfIterations = null;
|
||||||
|
try {
|
||||||
|
const preloginResponse = await this.apiService.postPrelogin(new PreloginRequest(email));
|
||||||
|
if (preloginResponse != null) {
|
||||||
|
this.kdf = preloginResponse.kdf;
|
||||||
|
this.kdfIterations = preloginResponse.kdfIterations;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (!(e instanceof ErrorResponse) || e.statusCode !== 404) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.cryptoService.makeKey(masterPassword, email, this.kdf, this.kdfIterations);
|
||||||
|
}
|
||||||
|
|
||||||
private async logInHelper(email: string, hashedPassword: string, key: SymmetricCryptoKey,
|
private async logInHelper(email: string, hashedPassword: string, key: SymmetricCryptoKey,
|
||||||
twoFactorProvider?: TwoFactorProviderType, twoFactorToken?: string, remember?: boolean): Promise<AuthResult> {
|
twoFactorProvider?: TwoFactorProviderType, twoFactorToken?: string, remember?: boolean): Promise<AuthResult> {
|
||||||
const storedTwoFactorToken = await this.tokenService.getTwoFactorToken(email);
|
const storedTwoFactorToken = await this.tokenService.getTwoFactorToken(email);
|
||||||
|
@ -235,7 +256,8 @@ export class AuthService {
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.tokenService.setTokens(tokenResponse.accessToken, tokenResponse.refreshToken);
|
await this.tokenService.setTokens(tokenResponse.accessToken, tokenResponse.refreshToken);
|
||||||
await this.userService.setUserIdAndEmail(this.tokenService.getUserId(), this.tokenService.getEmail());
|
await this.userService.setInformation(this.tokenService.getUserId(), this.tokenService.getEmail(),
|
||||||
|
this.kdf, this.kdfIterations);
|
||||||
if (this.setCryptoKeys) {
|
if (this.setCryptoKeys) {
|
||||||
await this.cryptoService.setKey(key);
|
await this.cryptoService.setKey(key);
|
||||||
await this.cryptoService.setKeyHash(hashedPassword);
|
await this.cryptoService.setKeyHash(hashedPassword);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { EncryptionType } from '../enums/encryptionType';
|
import { EncryptionType } from '../enums/encryptionType';
|
||||||
|
import { KdfType } from '../enums/kdfType';
|
||||||
|
|
||||||
import { CipherString } from '../models/domain/cipherString';
|
import { CipherString } from '../models/domain/cipherString';
|
||||||
import { EncryptedObject } from '../models/domain/encryptedObject';
|
import { EncryptedObject } from '../models/domain/encryptedObject';
|
||||||
|
@ -272,8 +273,19 @@ export class CryptoService implements CryptoServiceAbstraction {
|
||||||
await this.setKey(key);
|
await this.setKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
async makeKey(password: string, salt: string): Promise<SymmetricCryptoKey> {
|
async makeKey(password: string, salt: string, kdf: KdfType, kdfIterations: number):
|
||||||
const key = await this.cryptoFunctionService.pbkdf2(password, salt, 'sha256', 5000);
|
Promise<SymmetricCryptoKey> {
|
||||||
|
let key: ArrayBuffer = null;
|
||||||
|
if (kdf == null || kdf === KdfType.PBKDF2) {
|
||||||
|
if (kdfIterations == null) {
|
||||||
|
kdfIterations = 5000;
|
||||||
|
} else if (kdfIterations < 5000) {
|
||||||
|
throw new Error('PBKDF2 iteration minimum is 5000.');
|
||||||
|
}
|
||||||
|
key = await this.cryptoFunctionService.pbkdf2(password, salt, 'sha256', kdfIterations);
|
||||||
|
} else {
|
||||||
|
throw new Error('Unknown Kdf.');
|
||||||
|
}
|
||||||
return new SymmetricCryptoKey(key);
|
return new SymmetricCryptoKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,28 +5,37 @@ import { UserService as UserServiceAbstraction } from '../abstractions/user.serv
|
||||||
import { OrganizationData } from '../models/data/organizationData';
|
import { OrganizationData } from '../models/data/organizationData';
|
||||||
import { Organization } from '../models/domain/organization';
|
import { Organization } from '../models/domain/organization';
|
||||||
|
|
||||||
|
import { KdfType } from '../enums/kdfType';
|
||||||
|
|
||||||
const Keys = {
|
const Keys = {
|
||||||
userId: 'userId',
|
userId: 'userId',
|
||||||
userEmail: 'userEmail',
|
userEmail: 'userEmail',
|
||||||
stamp: 'securityStamp',
|
stamp: 'securityStamp',
|
||||||
|
kdf: 'kdf',
|
||||||
|
kdfIterations: 'kdfIterations',
|
||||||
organizationsPrefix: 'organizations_',
|
organizationsPrefix: 'organizations_',
|
||||||
};
|
};
|
||||||
|
|
||||||
export class UserService implements UserServiceAbstraction {
|
export class UserService implements UserServiceAbstraction {
|
||||||
userId: string;
|
private userId: string;
|
||||||
email: string;
|
private email: string;
|
||||||
stamp: string;
|
private stamp: string;
|
||||||
|
private kdf: KdfType;
|
||||||
|
private kdfIterations: number;
|
||||||
|
|
||||||
constructor(private tokenService: TokenService, private storageService: StorageService) {
|
constructor(private tokenService: TokenService, private storageService: StorageService) { }
|
||||||
}
|
|
||||||
|
|
||||||
setUserIdAndEmail(userId: string, email: string): Promise<any> {
|
setInformation(userId: string, email: string, kdf: KdfType, kdfIterations: number): Promise<any> {
|
||||||
this.email = email;
|
this.email = email;
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
|
this.kdf = kdf;
|
||||||
|
this.kdfIterations = kdfIterations;
|
||||||
|
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
this.storageService.save(Keys.userEmail, email),
|
this.storageService.save(Keys.userEmail, email),
|
||||||
this.storageService.save(Keys.userId, userId),
|
this.storageService.save(Keys.userId, userId),
|
||||||
|
this.storageService.save(Keys.kdf, kdf),
|
||||||
|
this.storageService.save(Keys.kdfIterations, kdfIterations),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,6 +71,24 @@ export class UserService implements UserServiceAbstraction {
|
||||||
return this.stamp;
|
return this.stamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getKdf(): Promise<KdfType> {
|
||||||
|
if (this.kdf != null) {
|
||||||
|
return this.kdf;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.kdf = await this.storageService.get<KdfType>(Keys.kdf);
|
||||||
|
return this.kdf;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getKdfIterations(): Promise<number> {
|
||||||
|
if (this.kdfIterations != null) {
|
||||||
|
return this.kdfIterations;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.kdfIterations = await this.storageService.get<number>(Keys.kdfIterations);
|
||||||
|
return this.kdfIterations;
|
||||||
|
}
|
||||||
|
|
||||||
async clear(): Promise<any> {
|
async clear(): Promise<any> {
|
||||||
const userId = await this.getUserId();
|
const userId = await this.getUserId();
|
||||||
|
|
||||||
|
@ -69,10 +96,14 @@ export class UserService implements UserServiceAbstraction {
|
||||||
this.storageService.remove(Keys.userId),
|
this.storageService.remove(Keys.userId),
|
||||||
this.storageService.remove(Keys.userEmail),
|
this.storageService.remove(Keys.userEmail),
|
||||||
this.storageService.remove(Keys.stamp),
|
this.storageService.remove(Keys.stamp),
|
||||||
|
this.storageService.remove(Keys.kdf),
|
||||||
|
this.storageService.remove(Keys.kdfIterations),
|
||||||
this.clearOrganizations(userId),
|
this.clearOrganizations(userId),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
this.userId = this.email = this.stamp = null;
|
this.userId = this.email = this.stamp = null;
|
||||||
|
this.kdf = null;
|
||||||
|
this.kdfIterations = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async isAuthenticated(): Promise<boolean> {
|
async isAuthenticated(): Promise<boolean> {
|
||||||
|
|
Loading…
Reference in New Issue