favalib 0.0.12 → 0.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/TwoFALibError.d.mts +1 -1
- package/build/TwoFALibError.mjs +1 -1
- package/build/TwoFaLib.d.mts +4 -4
- package/build/TwoFaLib.mjs +7 -7
- package/build/interfaces/CryptoLib.d.mts +11 -11
- package/build/interfaces/PasswordExtraDict.d.ts +2 -0
- package/build/main.d.mts +2 -2
- package/build/platformProviders/browser/cryptoLib.d.mts +6 -6
- package/build/platformProviders/browser/cryptoLib.mjs +21 -21
- package/build/platformProviders/node/cryptoLib.d.mts +4 -4
- package/build/platformProviders/node/cryptoLib.mjs +12 -12
- package/build/subclasses/ExportImportManager.d.mts +8 -8
- package/build/subclasses/ExportImportManager.mjs +14 -14
- package/build/subclasses/PersistentStorageManager.d.mts +16 -16
- package/build/subclasses/PersistentStorageManager.mjs +20 -20
- package/build/subclasses/StorageOperationsManager.d.mts +7 -7
- package/build/subclasses/StorageOperationsManager.mjs +7 -7
- package/build/utils/creationUtils.d.mts +18 -18
- package/build/utils/creationUtils.mjs +32 -32
- package/package.json +1 -1
- package/build/interfaces/PassphraseExtraDict.d.ts +0 -2
- /package/build/interfaces/{PassphraseExtraDict.js → PasswordExtraDict.js} +0 -0
|
@@ -14,7 +14,7 @@ export declare class TwoFALibError extends Error {
|
|
|
14
14
|
export declare class InitializationError extends TwoFALibError {
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
|
-
* Error thrown during authentication, e.g. wrong
|
|
17
|
+
* Error thrown during authentication, e.g. wrong password for locked vault.
|
|
18
18
|
*/
|
|
19
19
|
export declare class AuthenticationError extends TwoFALibError {
|
|
20
20
|
}
|
package/build/TwoFALibError.mjs
CHANGED
|
@@ -18,7 +18,7 @@ export class TwoFALibError extends Error {
|
|
|
18
18
|
export class InitializationError extends TwoFALibError {
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
|
-
* Error thrown during authentication, e.g. wrong
|
|
21
|
+
* Error thrown during authentication, e.g. wrong password for locked vault.
|
|
22
22
|
*/
|
|
23
23
|
export class AuthenticationError extends TwoFALibError {
|
|
24
24
|
}
|
package/build/TwoFaLib.d.mts
CHANGED
|
@@ -3,7 +3,7 @@ import type { PlatformProviders } from './interfaces/PlatformProviders.mjs';
|
|
|
3
3
|
import type { EncryptedPrivateKey, EncryptedSymmetricKey, PrivateKey, PublicKey, Salt, SymmetricKey } from './interfaces/CryptoLib.mjs';
|
|
4
4
|
import type { DeviceFriendlyName, DeviceType } from './interfaces/SyncTypes.mjs';
|
|
5
5
|
import type { TwoFaLibEventMapEvents } from './interfaces/Events.mjs';
|
|
6
|
-
import type {
|
|
6
|
+
import type { PasswordExtraDict } from './interfaces/PasswordExtraDict.js';
|
|
7
7
|
import type { Vault, VaultSyncState } from './interfaces/Vault.mjs';
|
|
8
8
|
import type { SaveFunction } from './interfaces/SaveFunction.mjs';
|
|
9
9
|
import type { FavaMeta } from './interfaces/FavaMeta.mjs';
|
|
@@ -35,7 +35,7 @@ declare class TwoFaLib extends TypedEventTarget<TwoFaLibEventMapEvents> {
|
|
|
35
35
|
* Constructs a new instance of TwoFaLib. If a serverUrl is provided, the library will use it for its sync operations.
|
|
36
36
|
* @param deviceType - The identifier for this device type (e.g. 2fa-cli).
|
|
37
37
|
* @param platformProviders - The platform-specific providers containing CryptoLib and other providers.
|
|
38
|
-
* @param
|
|
38
|
+
* @param passwordExtraDict - Additional words to be used for password strength evaluation.
|
|
39
39
|
* @param privateKey - The private key used for cryptographic operations.
|
|
40
40
|
* @param symmetricKey - The symmetric key used for cryptographic operations.
|
|
41
41
|
* @param encryptedPrivateKey - The encrypted private key
|
|
@@ -48,9 +48,9 @@ declare class TwoFaLib extends TypedEventTarget<TwoFaLibEventMapEvents> {
|
|
|
48
48
|
* @param syncState - The state of the sync, includes the serverUrl
|
|
49
49
|
* @returns A promise that resolves when initialization is complete.
|
|
50
50
|
* @throws {InitializationError} If some parameter has an invalid value
|
|
51
|
-
* @throws {AuthenticationError} If the provided
|
|
51
|
+
* @throws {AuthenticationError} If the provided password is incorrect.
|
|
52
52
|
*/
|
|
53
|
-
constructor(deviceType: DeviceType, platformProviders: PlatformProviders,
|
|
53
|
+
constructor(deviceType: DeviceType, platformProviders: PlatformProviders, passwordExtraDict: PasswordExtraDict, privateKey: PrivateKey, symmetricKey: SymmetricKey, encryptedPrivateKey: EncryptedPrivateKey, encryptedSymmetricKey: EncryptedSymmetricKey, salt: Salt, publicKey: PublicKey, favaMeta: FavaMeta, vault?: Vault, saveFunction?: SaveFunction, syncState?: VaultSyncState);
|
|
54
54
|
/**
|
|
55
55
|
* @returns The persistent storage manager instance which can be used to store data.
|
|
56
56
|
*/
|
package/build/TwoFaLib.mjs
CHANGED
|
@@ -31,7 +31,7 @@ class TwoFaLib extends TypedEventTarget {
|
|
|
31
31
|
* Constructs a new instance of TwoFaLib. If a serverUrl is provided, the library will use it for its sync operations.
|
|
32
32
|
* @param deviceType - The identifier for this device type (e.g. 2fa-cli).
|
|
33
33
|
* @param platformProviders - The platform-specific providers containing CryptoLib and other providers.
|
|
34
|
-
* @param
|
|
34
|
+
* @param passwordExtraDict - Additional words to be used for password strength evaluation.
|
|
35
35
|
* @param privateKey - The private key used for cryptographic operations.
|
|
36
36
|
* @param symmetricKey - The symmetric key used for cryptographic operations.
|
|
37
37
|
* @param encryptedPrivateKey - The encrypted private key
|
|
@@ -44,9 +44,9 @@ class TwoFaLib extends TypedEventTarget {
|
|
|
44
44
|
* @param syncState - The state of the sync, includes the serverUrl
|
|
45
45
|
* @returns A promise that resolves when initialization is complete.
|
|
46
46
|
* @throws {InitializationError} If some parameter has an invalid value
|
|
47
|
-
* @throws {AuthenticationError} If the provided
|
|
47
|
+
* @throws {AuthenticationError} If the provided password is incorrect.
|
|
48
48
|
*/
|
|
49
|
-
constructor(deviceType, platformProviders,
|
|
49
|
+
constructor(deviceType, platformProviders, passwordExtraDict, privateKey, symmetricKey, encryptedPrivateKey, encryptedSymmetricKey, salt, publicKey, favaMeta, vault, saveFunction, syncState) {
|
|
50
50
|
super();
|
|
51
51
|
if (!deviceType) {
|
|
52
52
|
throw new InitializationError('Device type is required');
|
|
@@ -61,8 +61,8 @@ class TwoFaLib extends TypedEventTarget {
|
|
|
61
61
|
favaMeta.deviceFriendlyName.length > 256) {
|
|
62
62
|
throw new InitializationError('Device friendly name is too long, max 256 characters');
|
|
63
63
|
}
|
|
64
|
-
if (
|
|
65
|
-
throw new InitializationError('
|
|
64
|
+
if (passwordExtraDict?.length === 0) {
|
|
65
|
+
throw new InitializationError('Password extra dictionary is required and must contain at least one element (eg phone)');
|
|
66
66
|
}
|
|
67
67
|
this.favaMeta = favaMeta;
|
|
68
68
|
this.deviceType = deviceType;
|
|
@@ -73,7 +73,7 @@ class TwoFaLib extends TypedEventTarget {
|
|
|
73
73
|
['libraryLoader', new LibraryLoader(platformProviders)],
|
|
74
74
|
[
|
|
75
75
|
'persistentStorageManager',
|
|
76
|
-
new PersistentStorageManager(this.mediator,
|
|
76
|
+
new PersistentStorageManager(this.mediator, passwordExtraDict, favaMeta, privateKey, symmetricKey, encryptedPrivateKey, encryptedSymmetricKey, salt, saveFunction),
|
|
77
77
|
],
|
|
78
78
|
['vaultDataManager', new VaultDataManager(this.mediator)],
|
|
79
79
|
['commandManager', new CommandManager(this.mediator)],
|
|
@@ -81,7 +81,7 @@ class TwoFaLib extends TypedEventTarget {
|
|
|
81
81
|
['storageOperationsManager', new StorageOperationsManager(this.mediator)],
|
|
82
82
|
[
|
|
83
83
|
'exportImportManager',
|
|
84
|
-
new ExportImportManager(this.mediator,
|
|
84
|
+
new ExportImportManager(this.mediator, passwordExtraDict),
|
|
85
85
|
],
|
|
86
86
|
['dispatchLibEvent', this.dispatchLibEvent.bind(this)],
|
|
87
87
|
['log', this.log.bind(this)],
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { Tagged } from 'type-fest';
|
|
2
2
|
export type Encrypted<T extends string> = Tagged<T, 'Encrypted'>;
|
|
3
|
-
/** Represents a
|
|
4
|
-
export type
|
|
5
|
-
/** Represents a
|
|
6
|
-
export type
|
|
3
|
+
/** Represents a password */
|
|
4
|
+
export type Password = Tagged<string, 'Password'>;
|
|
5
|
+
/** Represents a passwordHash */
|
|
6
|
+
export type PasswordHash = Tagged<string, 'PasswordHash'>;
|
|
7
7
|
/** Represents a salt (base64 encoded) */
|
|
8
8
|
export type Salt = Tagged<string, 'Salt'>;
|
|
9
9
|
/** Represents a private key */
|
|
@@ -33,12 +33,12 @@ interface CryptoLib {
|
|
|
33
33
|
getRandomBytes: (count: number) => Promise<Uint8Array>;
|
|
34
34
|
/**
|
|
35
35
|
* Creates the keys required for further operations.
|
|
36
|
-
* It first creates a public/private key pair, with the private key being encrypted using the
|
|
36
|
+
* It first creates a public/private key pair, with the private key being encrypted using the password.
|
|
37
37
|
* It then generates a symmetricKey. It will then encrypt this symmetricKey using the generated public key.
|
|
38
|
-
* @param
|
|
38
|
+
* @param password - The password to encrypt the private key with
|
|
39
39
|
* @returns A promise that resolves to an object containing the encrypted private key, encrypted symmetric key and public key
|
|
40
40
|
*/
|
|
41
|
-
createKeys: (
|
|
41
|
+
createKeys: (password: Password) => Promise<{
|
|
42
42
|
privateKey: PrivateKey;
|
|
43
43
|
symmetricKey: SymmetricKey;
|
|
44
44
|
encryptedPrivateKey: EncryptedPrivateKey;
|
|
@@ -50,10 +50,10 @@ interface CryptoLib {
|
|
|
50
50
|
* Decrypts the keys required for further operations
|
|
51
51
|
* @param encryptedPrivateKey - The encrypted private key
|
|
52
52
|
* @param encryptedSymmetricKey - The encrypted symmetric key
|
|
53
|
-
* @param
|
|
53
|
+
* @param password - The password to decrypt the private key with
|
|
54
54
|
* @returns A promise that resolves to an object containing the decrypted private, symmetric and public key
|
|
55
55
|
*/
|
|
56
|
-
decryptKeys: (encryptedPrivateKey: EncryptedPrivateKey, encryptedSymmetricKey: EncryptedSymmetricKey, salt: Salt,
|
|
56
|
+
decryptKeys: (encryptedPrivateKey: EncryptedPrivateKey, encryptedSymmetricKey: EncryptedSymmetricKey, salt: Salt, password: Password) => Promise<{
|
|
57
57
|
privateKey: PrivateKey;
|
|
58
58
|
symmetricKey: SymmetricKey;
|
|
59
59
|
publicKey: PublicKey;
|
|
@@ -62,10 +62,10 @@ interface CryptoLib {
|
|
|
62
62
|
* Encrypts the keys required for further operation
|
|
63
63
|
* @param privateKey - The private key to encrypt
|
|
64
64
|
* @param symmetricKey - The symmetric key to encrypt
|
|
65
|
-
* @param
|
|
65
|
+
* @param password - The password to encrypt the private key with
|
|
66
66
|
* @returns A promise that resolves to an object containing the encrypted private and symmetricKey key
|
|
67
67
|
*/
|
|
68
|
-
encryptKeys: (privateKey: PrivateKey, symmetricKey: SymmetricKey, salt: Salt,
|
|
68
|
+
encryptKeys: (privateKey: PrivateKey, symmetricKey: SymmetricKey, salt: Salt, password: Password) => Promise<{
|
|
69
69
|
encryptedPrivateKey: EncryptedPrivateKey;
|
|
70
70
|
encryptedSymmetricKey: EncryptedSymmetricKey;
|
|
71
71
|
}>;
|
package/build/main.d.mts
CHANGED
|
@@ -2,7 +2,7 @@ import TwoFaLib from './TwoFaLib.mjs';
|
|
|
2
2
|
import type Entry from './interfaces/Entry.mjs';
|
|
3
3
|
import type { EntryId, NewEntry, EntryMeta, EntryType, TotpPayload, Token, EntryMetaWithToken } from './interfaces/Entry.mjs';
|
|
4
4
|
import type CryptoLib from './interfaces/CryptoLib.mjs';
|
|
5
|
-
import type { Encrypted, EncryptedPrivateKey, EncryptedSymmetricKey, EncryptedPublicKey, PrivateKey, SymmetricKey, PublicKey,
|
|
5
|
+
import type { Encrypted, EncryptedPrivateKey, EncryptedSymmetricKey, EncryptedPublicKey, PrivateKey, SymmetricKey, PublicKey, Password, Salt } from './interfaces/CryptoLib.mjs';
|
|
6
6
|
import type { PublicSyncDevice, DeviceId, DeviceType, DeviceFriendlyName, DeviceInfo } from './interfaces/SyncTypes.mjs';
|
|
7
7
|
import type { EncryptedVaultStateString, LockedRepresentationString } from './interfaces/Vault.mjs';
|
|
8
8
|
import type { SaveFunction } from './interfaces/SaveFunction.mjs';
|
|
@@ -11,4 +11,4 @@ import { TwoFALibError, InitializationError, AuthenticationError, EntryNotFoundE
|
|
|
11
11
|
import { TwoFaLibEvent } from './TwoFaLibEvent.mjs';
|
|
12
12
|
import { getTwoFaLibVaultCreationUtils } from './utils/creationUtils.mjs';
|
|
13
13
|
export { TwoFaLib, TwoFALibError, getTwoFaLibVaultCreationUtils, InitializationError, AuthenticationError, EntryNotFoundError, TokenGenerationError, TwoFaLibEvent, };
|
|
14
|
-
export type { Entry, EntryId, NewEntry, EntryMeta, EntryMetaWithToken, EntryType, TotpPayload, Token, EncryptedVaultStateString, LockedRepresentationString, CryptoLib, Encrypted, EncryptedPrivateKey, EncryptedPublicKey, EncryptedSymmetricKey, PrivateKey, SymmetricKey, PublicKey,
|
|
14
|
+
export type { Entry, EntryId, NewEntry, EntryMeta, EntryMetaWithToken, EntryType, TotpPayload, Token, EncryptedVaultStateString, LockedRepresentationString, CryptoLib, Encrypted, EncryptedPrivateKey, EncryptedPublicKey, EncryptedSymmetricKey, PrivateKey, SymmetricKey, PublicKey, Password, Salt, DeviceId, DeviceType, DeviceFriendlyName, DeviceInfo, PublicSyncDevice, SaveFunction, PlatformProviders, };
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type CryptoLib from '../../interfaces/CryptoLib.mjs';
|
|
2
|
-
import type { Encrypted, EncryptedPrivateKey, EncryptedSymmetricKey,
|
|
2
|
+
import type { Encrypted, EncryptedPrivateKey, EncryptedSymmetricKey, Password, PasswordHash, PrivateKey, PublicKey, Salt, SymmetricKey, SyncKey } from '../../interfaces/CryptoLib.mjs';
|
|
3
3
|
/**
|
|
4
4
|
* Create a password hash
|
|
5
5
|
* @param salt - The salt to use
|
|
6
|
-
* @param
|
|
6
|
+
* @param password - The password to hash
|
|
7
7
|
* @returns The calculated password hash
|
|
8
8
|
*/
|
|
9
|
-
export declare const
|
|
9
|
+
export declare const generatePasswordHash: (salt: Salt, password: string) => Promise<PasswordHash>;
|
|
10
10
|
/**
|
|
11
11
|
* @inheritdoc
|
|
12
12
|
*/
|
|
@@ -18,7 +18,7 @@ declare class BrowserCryptoLib implements CryptoLib {
|
|
|
18
18
|
/**
|
|
19
19
|
* @inheritdoc
|
|
20
20
|
*/
|
|
21
|
-
createKeys(
|
|
21
|
+
createKeys(password: Password): Promise<{
|
|
22
22
|
privateKey: PrivateKey;
|
|
23
23
|
symmetricKey: SymmetricKey;
|
|
24
24
|
encryptedPrivateKey: EncryptedPrivateKey;
|
|
@@ -29,14 +29,14 @@ declare class BrowserCryptoLib implements CryptoLib {
|
|
|
29
29
|
/**
|
|
30
30
|
* @inheritdoc
|
|
31
31
|
*/
|
|
32
|
-
encryptKeys(privateKey: PrivateKey, symmetricKey: SymmetricKey, salt: Salt,
|
|
32
|
+
encryptKeys(privateKey: PrivateKey, symmetricKey: SymmetricKey, salt: Salt, password: Password): Promise<{
|
|
33
33
|
encryptedPrivateKey: EncryptedPrivateKey;
|
|
34
34
|
encryptedSymmetricKey: EncryptedSymmetricKey;
|
|
35
35
|
}>;
|
|
36
36
|
/**
|
|
37
37
|
* @inheritdoc
|
|
38
38
|
*/
|
|
39
|
-
decryptKeys(encryptedPrivateKey: EncryptedPrivateKey, encryptedSymmetricKey: EncryptedSymmetricKey, salt: Salt,
|
|
39
|
+
decryptKeys(encryptedPrivateKey: EncryptedPrivateKey, encryptedSymmetricKey: EncryptedSymmetricKey, salt: Salt, password: Password): Promise<{
|
|
40
40
|
privateKey: PrivateKey;
|
|
41
41
|
publicKey: PublicKey;
|
|
42
42
|
symmetricKey: SymmetricKey;
|
|
@@ -14,12 +14,12 @@ const normalizeLineEndings = (str) => {
|
|
|
14
14
|
/**
|
|
15
15
|
* Create a password hash
|
|
16
16
|
* @param salt - The salt to use
|
|
17
|
-
* @param
|
|
17
|
+
* @param password - The password to hash
|
|
18
18
|
* @returns The calculated password hash
|
|
19
19
|
*/
|
|
20
|
-
export const
|
|
20
|
+
export const generatePasswordHash = (salt, password) => {
|
|
21
21
|
return argon2id({
|
|
22
|
-
password
|
|
22
|
+
password,
|
|
23
23
|
salt,
|
|
24
24
|
parallelism: 1,
|
|
25
25
|
iterations: 256,
|
|
@@ -41,12 +41,12 @@ class BrowserCryptoLib {
|
|
|
41
41
|
/**
|
|
42
42
|
* @inheritdoc
|
|
43
43
|
*/
|
|
44
|
-
async createKeys(
|
|
44
|
+
async createKeys(password) {
|
|
45
45
|
// create random salt
|
|
46
46
|
const salt = uint8ArrayToBase64(window.crypto.getRandomValues(new Uint8Array(16)));
|
|
47
47
|
// create passwordHash
|
|
48
|
-
const
|
|
49
|
-
const { privateKey, encryptedPrivateKey, publicKey } = await this.createKeyPair(
|
|
48
|
+
const passwordHash = await generatePasswordHash(salt, password);
|
|
49
|
+
const { privateKey, encryptedPrivateKey, publicKey } = await this.createKeyPair(passwordHash);
|
|
50
50
|
const symmetricKey = await this.createSymmetricKey();
|
|
51
51
|
const encryptedSymmetricKey = await this.encrypt(publicKey, symmetricKey);
|
|
52
52
|
return {
|
|
@@ -61,10 +61,10 @@ class BrowserCryptoLib {
|
|
|
61
61
|
/**
|
|
62
62
|
* @inheritdoc
|
|
63
63
|
*/
|
|
64
|
-
async encryptKeys(privateKey, symmetricKey, salt,
|
|
64
|
+
async encryptKeys(privateKey, symmetricKey, salt, password) {
|
|
65
65
|
// recreate passwordHash
|
|
66
|
-
const
|
|
67
|
-
const encryptedPrivateKey = await this.encryptPrivateKey(privateKey,
|
|
66
|
+
const passwordHash = await generatePasswordHash(salt, password);
|
|
67
|
+
const encryptedPrivateKey = await this.encryptPrivateKey(privateKey, passwordHash);
|
|
68
68
|
const publicKey = await this.getPublicKeyFromPrivateKey(privateKey);
|
|
69
69
|
const encryptedSymmetricKey = await this.encrypt(publicKey, symmetricKey);
|
|
70
70
|
return {
|
|
@@ -75,10 +75,10 @@ class BrowserCryptoLib {
|
|
|
75
75
|
/**
|
|
76
76
|
* @inheritdoc
|
|
77
77
|
*/
|
|
78
|
-
async decryptKeys(encryptedPrivateKey, encryptedSymmetricKey, salt,
|
|
78
|
+
async decryptKeys(encryptedPrivateKey, encryptedSymmetricKey, salt, password) {
|
|
79
79
|
// recreate passwordHash
|
|
80
|
-
const
|
|
81
|
-
const { privateKey, publicKey } = await this.decryptPrivateKey(encryptedPrivateKey,
|
|
80
|
+
const passwordHash = await generatePasswordHash(salt, password);
|
|
81
|
+
const { privateKey, publicKey } = await this.decryptPrivateKey(encryptedPrivateKey, passwordHash);
|
|
82
82
|
const symmetricKey = (await this.decrypt(privateKey, encryptedSymmetricKey));
|
|
83
83
|
return { privateKey, publicKey, symmetricKey };
|
|
84
84
|
}
|
|
@@ -146,18 +146,18 @@ class BrowserCryptoLib {
|
|
|
146
146
|
});
|
|
147
147
|
return uint8ArrayToBase64(key);
|
|
148
148
|
}
|
|
149
|
-
async encryptPrivateKey(privateKey,
|
|
149
|
+
async encryptPrivateKey(privateKey, passwordHash) {
|
|
150
150
|
const privateKeyObj = forge.pki.privateKeyFromPem(privateKey);
|
|
151
|
-
const encryptedPrivateKey = forge.pki.encryptRsaPrivateKey(privateKeyObj,
|
|
151
|
+
const encryptedPrivateKey = forge.pki.encryptRsaPrivateKey(privateKeyObj, passwordHash, {
|
|
152
152
|
algorithm: 'aes256',
|
|
153
153
|
});
|
|
154
154
|
return Promise.resolve(encryptedPrivateKey);
|
|
155
155
|
}
|
|
156
|
-
async decryptPrivateKey(encryptedPrivateKey,
|
|
156
|
+
async decryptPrivateKey(encryptedPrivateKey, passwordHash) {
|
|
157
157
|
try {
|
|
158
|
-
const privateKeyPem = forge.pki.decryptRsaPrivateKey(encryptedPrivateKey,
|
|
158
|
+
const privateKeyPem = forge.pki.decryptRsaPrivateKey(encryptedPrivateKey, passwordHash);
|
|
159
159
|
if (!privateKeyPem) {
|
|
160
|
-
throw new CryptoError('Invalid
|
|
160
|
+
throw new CryptoError('Invalid password');
|
|
161
161
|
}
|
|
162
162
|
const privateKey = forge.pki.privateKeyToPem(privateKeyPem);
|
|
163
163
|
const publicKey = forge.pki.publicKeyToPem(forge.pki.setRsaPublicKey(privateKeyPem.n, privateKeyPem.e));
|
|
@@ -169,8 +169,8 @@ class BrowserCryptoLib {
|
|
|
169
169
|
catch (err) {
|
|
170
170
|
// eslint-disable-next-line no-restricted-globals
|
|
171
171
|
if (err instanceof Error) {
|
|
172
|
-
if (err.message === 'Invalid
|
|
173
|
-
throw new CryptoError('Invalid
|
|
172
|
+
if (err.message === 'Invalid password') {
|
|
173
|
+
throw new CryptoError('Invalid password');
|
|
174
174
|
}
|
|
175
175
|
if (err.message.includes('Unsupported private key')) {
|
|
176
176
|
throw new CryptoError('Invalid private key');
|
|
@@ -179,7 +179,7 @@ class BrowserCryptoLib {
|
|
|
179
179
|
throw err;
|
|
180
180
|
}
|
|
181
181
|
}
|
|
182
|
-
async createKeyPair(
|
|
182
|
+
async createKeyPair(password) {
|
|
183
183
|
return new Promise((resolve, reject) => {
|
|
184
184
|
forge.pki.rsa.generateKeyPair({ bits: 4096 }, (err, keyPair) => {
|
|
185
185
|
if (err) {
|
|
@@ -188,7 +188,7 @@ class BrowserCryptoLib {
|
|
|
188
188
|
else {
|
|
189
189
|
const publicKey = forge.pki.publicKeyToPem(keyPair.publicKey);
|
|
190
190
|
const privateKey = forge.pki.privateKeyToPem(keyPair.privateKey);
|
|
191
|
-
const encryptedPrivateKey = forge.pki.encryptRsaPrivateKey(keyPair.privateKey,
|
|
191
|
+
const encryptedPrivateKey = forge.pki.encryptRsaPrivateKey(keyPair.privateKey, password, {
|
|
192
192
|
algorithm: 'aes256',
|
|
193
193
|
});
|
|
194
194
|
resolve({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type CryptoLib from '../../interfaces/CryptoLib.mjs';
|
|
2
|
-
import type { Encrypted, EncryptedPrivateKey, EncryptedSymmetricKey,
|
|
2
|
+
import type { Encrypted, EncryptedPrivateKey, EncryptedSymmetricKey, Password, PrivateKey, PublicKey, Salt, SymmetricKey, SyncKey } from '../../interfaces/CryptoLib.mjs';
|
|
3
3
|
/**
|
|
4
4
|
* @inheritdoc
|
|
5
5
|
*/
|
|
@@ -11,7 +11,7 @@ declare class NodeCryptoLib implements CryptoLib {
|
|
|
11
11
|
/**
|
|
12
12
|
* @inheritdoc
|
|
13
13
|
*/
|
|
14
|
-
createKeys(
|
|
14
|
+
createKeys(password: Password): Promise<{
|
|
15
15
|
privateKey: PrivateKey;
|
|
16
16
|
symmetricKey: SymmetricKey;
|
|
17
17
|
publicKey: PublicKey;
|
|
@@ -22,14 +22,14 @@ declare class NodeCryptoLib implements CryptoLib {
|
|
|
22
22
|
/**
|
|
23
23
|
* @inheritdoc
|
|
24
24
|
*/
|
|
25
|
-
encryptKeys(privateKey: PrivateKey, symmetricKey: SymmetricKey, salt: Salt,
|
|
25
|
+
encryptKeys(privateKey: PrivateKey, symmetricKey: SymmetricKey, salt: Salt, password: Password): Promise<{
|
|
26
26
|
encryptedPrivateKey: EncryptedPrivateKey;
|
|
27
27
|
encryptedSymmetricKey: EncryptedSymmetricKey;
|
|
28
28
|
}>;
|
|
29
29
|
/**
|
|
30
30
|
* @inheritdoc
|
|
31
31
|
*/
|
|
32
|
-
decryptKeys(encryptedPrivateKey: EncryptedPrivateKey, encryptedSymmetricKey: EncryptedSymmetricKey, salt: Salt,
|
|
32
|
+
decryptKeys(encryptedPrivateKey: EncryptedPrivateKey, encryptedSymmetricKey: EncryptedSymmetricKey, salt: Salt, password: Password): Promise<{
|
|
33
33
|
privateKey: PrivateKey;
|
|
34
34
|
publicKey: PublicKey;
|
|
35
35
|
symmetricKey: SymmetricKey;
|
|
@@ -4,7 +4,7 @@ import { generateKeyPair as generateKeyPairCb, generateKey as generateKeyCb, pub
|
|
|
4
4
|
import { argon2id } from 'hash-wasm';
|
|
5
5
|
import { toUint8Array } from 'uint8array-extras';
|
|
6
6
|
import { CryptoError } from '../../TwoFALibError.mjs';
|
|
7
|
-
import {
|
|
7
|
+
import { generatePasswordHash } from '../browser/cryptoLib.mjs';
|
|
8
8
|
const generateKeyPair = promisify(generateKeyPairCb);
|
|
9
9
|
const generateKey = promisify(generateKeyCb);
|
|
10
10
|
/**
|
|
@@ -20,11 +20,11 @@ class NodeCryptoLib {
|
|
|
20
20
|
/**
|
|
21
21
|
* @inheritdoc
|
|
22
22
|
*/
|
|
23
|
-
async createKeys(
|
|
23
|
+
async createKeys(password) {
|
|
24
24
|
// create random salt
|
|
25
25
|
const salt = randomBytes(16).toString('base64');
|
|
26
26
|
// create passwordHash
|
|
27
|
-
const
|
|
27
|
+
const passwordHash = await generatePasswordHash(salt, password);
|
|
28
28
|
// Generate public/private key pair
|
|
29
29
|
const { publicKey, privateKey: encryptedPrivateKey } = await generateKeyPair('rsa', {
|
|
30
30
|
modulusLength: 4096,
|
|
@@ -36,13 +36,13 @@ class NodeCryptoLib {
|
|
|
36
36
|
type: 'pkcs8',
|
|
37
37
|
format: 'pem',
|
|
38
38
|
cipher: 'aes-256-cbc',
|
|
39
|
-
passphrase:
|
|
39
|
+
passphrase: passwordHash,
|
|
40
40
|
},
|
|
41
41
|
});
|
|
42
42
|
// Create and encrypt symmetric key with public key
|
|
43
43
|
const symmetricKey = await this.createSymmetricKey();
|
|
44
44
|
const encryptedSymmetricKey = await this.encrypt(publicKey, symmetricKey);
|
|
45
|
-
const { privateKey } = await this.decryptKeys(encryptedPrivateKey, encryptedSymmetricKey, salt,
|
|
45
|
+
const { privateKey } = await this.decryptKeys(encryptedPrivateKey, encryptedSymmetricKey, salt, password);
|
|
46
46
|
return {
|
|
47
47
|
privateKey: privateKey,
|
|
48
48
|
symmetricKey,
|
|
@@ -55,9 +55,9 @@ class NodeCryptoLib {
|
|
|
55
55
|
/**
|
|
56
56
|
* @inheritdoc
|
|
57
57
|
*/
|
|
58
|
-
async encryptKeys(privateKey, symmetricKey, salt,
|
|
58
|
+
async encryptKeys(privateKey, symmetricKey, salt, password) {
|
|
59
59
|
// recreate passwordHash
|
|
60
|
-
const
|
|
60
|
+
const passwordHash = await generatePasswordHash(salt, password);
|
|
61
61
|
// Encrypt private key
|
|
62
62
|
const privateKeyObject = createPrivateKey({
|
|
63
63
|
key: privateKey,
|
|
@@ -67,7 +67,7 @@ class NodeCryptoLib {
|
|
|
67
67
|
type: 'pkcs8',
|
|
68
68
|
format: 'pem',
|
|
69
69
|
cipher: 'aes-256-cbc',
|
|
70
|
-
passphrase:
|
|
70
|
+
passphrase: passwordHash,
|
|
71
71
|
});
|
|
72
72
|
// Encrypt symmetric key with public key
|
|
73
73
|
const publicKeyObject = createPublicKey(privateKeyObject);
|
|
@@ -84,9 +84,9 @@ class NodeCryptoLib {
|
|
|
84
84
|
/**
|
|
85
85
|
* @inheritdoc
|
|
86
86
|
*/
|
|
87
|
-
async decryptKeys(encryptedPrivateKey, encryptedSymmetricKey, salt,
|
|
87
|
+
async decryptKeys(encryptedPrivateKey, encryptedSymmetricKey, salt, password) {
|
|
88
88
|
// recreate passwordHash
|
|
89
|
-
const
|
|
89
|
+
const passwordHash = await generatePasswordHash(salt, password);
|
|
90
90
|
let privateKeyObject;
|
|
91
91
|
let privateKey;
|
|
92
92
|
try {
|
|
@@ -94,7 +94,7 @@ class NodeCryptoLib {
|
|
|
94
94
|
key: encryptedPrivateKey,
|
|
95
95
|
type: 'pkcs8',
|
|
96
96
|
format: 'pem',
|
|
97
|
-
passphrase:
|
|
97
|
+
passphrase: passwordHash,
|
|
98
98
|
});
|
|
99
99
|
privateKey = privateKeyObject.export({
|
|
100
100
|
type: 'pkcs8',
|
|
@@ -105,7 +105,7 @@ class NodeCryptoLib {
|
|
|
105
105
|
// eslint-disable-next-line no-restricted-globals
|
|
106
106
|
if (err instanceof Error && 'code' in err) {
|
|
107
107
|
if (err.code === 'ERR_OSSL_BAD_DECRYPT') {
|
|
108
|
-
throw new CryptoError('Invalid
|
|
108
|
+
throw new CryptoError('Invalid password');
|
|
109
109
|
}
|
|
110
110
|
if (err.code === 'ERR_OSSL_UNSUPPORTED') {
|
|
111
111
|
throw new CryptoError('Invalid private key');
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { EntryId } from '../interfaces/Entry.mjs';
|
|
2
|
-
import type {
|
|
2
|
+
import type { PasswordExtraDict } from '../interfaces/PasswordExtraDict.js';
|
|
3
3
|
import type TwoFaLibMediator from '../TwoFaLibMediator.mjs';
|
|
4
4
|
/**
|
|
5
5
|
* Manages the export and import of entries in various formats.
|
|
6
6
|
*/
|
|
7
7
|
declare class ExportImportManager {
|
|
8
8
|
private readonly mediator;
|
|
9
|
-
private readonly
|
|
9
|
+
private readonly passwordExtraDict;
|
|
10
10
|
/**
|
|
11
11
|
* Constructs a new instance of ExportImportManager.
|
|
12
12
|
* @param mediator - The mediator for accessing other components.
|
|
13
|
-
* @param
|
|
13
|
+
* @param passwordExtraDict - Additional words to be used for password strength evaluation.
|
|
14
14
|
*/
|
|
15
|
-
constructor(mediator: TwoFaLibMediator,
|
|
15
|
+
constructor(mediator: TwoFaLibMediator, passwordExtraDict: PasswordExtraDict);
|
|
16
16
|
private get libraryLoader();
|
|
17
17
|
private get vaultDataManager();
|
|
18
18
|
private get vaultOperationsManager();
|
|
@@ -21,21 +21,21 @@ declare class ExportImportManager {
|
|
|
21
21
|
* Export entries in the specified format, optionally (when a password is provided) encrypted.
|
|
22
22
|
* If the password is not provided, the user be warned about the dangers of exporting clear text.
|
|
23
23
|
* @param format - The export format ('text' or 'html').
|
|
24
|
-
* @param
|
|
24
|
+
* @param password - Optional password for encryption.
|
|
25
25
|
* @param userWasWarnedAboutExportingClearText - Whether the user was warned about exporting clear text.
|
|
26
26
|
* @returns A promise that resolves to the exported data as a string.
|
|
27
27
|
*/
|
|
28
|
-
exportEntries(format: 'text' | 'html',
|
|
28
|
+
exportEntries(format: 'text' | 'html', password?: string, userWasWarnedAboutExportingClearText?: boolean): Promise<string>;
|
|
29
29
|
private generateTextExport;
|
|
30
30
|
private generateHtmlExport;
|
|
31
31
|
/**
|
|
32
32
|
* Import entries from a text file, optionally (when a password is provided) decrypt first
|
|
33
33
|
* @param fileContents - The contents of the text file.
|
|
34
|
-
* @param
|
|
34
|
+
* @param password - Optional password for decryption.
|
|
35
35
|
* @returns A promise that resolves to an array of objects, each containing the line number,
|
|
36
36
|
* the EntryId or null if it was not a valid entry and the error if there was one.
|
|
37
37
|
*/
|
|
38
|
-
importFromTextFile(fileContents: string,
|
|
38
|
+
importFromTextFile(fileContents: string, password?: string): Promise<{
|
|
39
39
|
lineNr: number;
|
|
40
40
|
entryId: EntryId | null;
|
|
41
41
|
error: unknown;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { parseOtpUri, generateHtmlExport, generateTextExport, processImportLines, encryptExport, decryptExport, } from '../utils/exportImportUtils.mjs';
|
|
2
2
|
import { getDataFromQRImage } from '../utils/qrUtils.mjs';
|
|
3
3
|
import { ExportImportError } from '../TwoFALibError.mjs';
|
|
4
|
-
import {
|
|
4
|
+
import { validatePasswordStrength } from '../utils/creationUtils.mjs';
|
|
5
5
|
/**
|
|
6
6
|
* Manages the export and import of entries in various formats.
|
|
7
7
|
*/
|
|
@@ -9,11 +9,11 @@ class ExportImportManager {
|
|
|
9
9
|
/**
|
|
10
10
|
* Constructs a new instance of ExportImportManager.
|
|
11
11
|
* @param mediator - The mediator for accessing other components.
|
|
12
|
-
* @param
|
|
12
|
+
* @param passwordExtraDict - Additional words to be used for password strength evaluation.
|
|
13
13
|
*/
|
|
14
|
-
constructor(mediator,
|
|
14
|
+
constructor(mediator, passwordExtraDict) {
|
|
15
15
|
this.mediator = mediator;
|
|
16
|
-
this.
|
|
16
|
+
this.passwordExtraDict = passwordExtraDict;
|
|
17
17
|
}
|
|
18
18
|
get libraryLoader() {
|
|
19
19
|
return this.mediator.getComponent('libraryLoader');
|
|
@@ -31,13 +31,13 @@ class ExportImportManager {
|
|
|
31
31
|
* Export entries in the specified format, optionally (when a password is provided) encrypted.
|
|
32
32
|
* If the password is not provided, the user be warned about the dangers of exporting clear text.
|
|
33
33
|
* @param format - The export format ('text' or 'html').
|
|
34
|
-
* @param
|
|
34
|
+
* @param password - Optional password for encryption.
|
|
35
35
|
* @param userWasWarnedAboutExportingClearText - Whether the user was warned about exporting clear text.
|
|
36
36
|
* @returns A promise that resolves to the exported data as a string.
|
|
37
37
|
*/
|
|
38
|
-
async exportEntries(format,
|
|
38
|
+
async exportEntries(format, password, userWasWarnedAboutExportingClearText) {
|
|
39
39
|
let exportData;
|
|
40
|
-
if (!
|
|
40
|
+
if (!password && !userWasWarnedAboutExportingClearText) {
|
|
41
41
|
throw new ExportImportError('User was not warned about the dangers of unencrypted exporting');
|
|
42
42
|
}
|
|
43
43
|
if (format === 'text') {
|
|
@@ -49,9 +49,9 @@ class ExportImportManager {
|
|
|
49
49
|
else {
|
|
50
50
|
throw new ExportImportError('Invalid export format');
|
|
51
51
|
}
|
|
52
|
-
if (
|
|
53
|
-
await
|
|
54
|
-
return encryptExport(this.libraryLoader.getOpenPGPLib(), exportData,
|
|
52
|
+
if (password) {
|
|
53
|
+
await validatePasswordStrength(this.libraryLoader, this.passwordExtraDict, password);
|
|
54
|
+
return encryptExport(this.libraryLoader.getOpenPGPLib(), exportData, password);
|
|
55
55
|
}
|
|
56
56
|
return exportData;
|
|
57
57
|
}
|
|
@@ -65,13 +65,13 @@ class ExportImportManager {
|
|
|
65
65
|
/**
|
|
66
66
|
* Import entries from a text file, optionally (when a password is provided) decrypt first
|
|
67
67
|
* @param fileContents - The contents of the text file.
|
|
68
|
-
* @param
|
|
68
|
+
* @param password - Optional password for decryption.
|
|
69
69
|
* @returns A promise that resolves to an array of objects, each containing the line number,
|
|
70
70
|
* the EntryId or null if it was not a valid entry and the error if there was one.
|
|
71
71
|
*/
|
|
72
|
-
async importFromTextFile(fileContents,
|
|
73
|
-
if (
|
|
74
|
-
const decrypted = await decryptExport(this.libraryLoader.getOpenPGPLib(), fileContents,
|
|
72
|
+
async importFromTextFile(fileContents, password) {
|
|
73
|
+
if (password) {
|
|
74
|
+
const decrypted = await decryptExport(this.libraryLoader.getOpenPGPLib(), fileContents, password);
|
|
75
75
|
return this.importFromTextFile(decrypted);
|
|
76
76
|
}
|
|
77
77
|
const lines = fileContents.trim().split('\n');
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { EncryptedPrivateKey, EncryptedSymmetricKey,
|
|
1
|
+
import type { EncryptedPrivateKey, EncryptedSymmetricKey, Password, PrivateKey, Salt, SymmetricKey } from '../interfaces/CryptoLib.mjs';
|
|
2
2
|
import { EncryptedVaultStateString, LockedRepresentationString } from '../interfaces/Vault.mjs';
|
|
3
3
|
import type TwoFaLibMediator from '../TwoFaLibMediator.mjs';
|
|
4
4
|
import type { FavaMeta } from '../interfaces/FavaMeta.mjs';
|
|
5
|
-
import type {
|
|
5
|
+
import type { PasswordExtraDict } from '../interfaces/PasswordExtraDict.js';
|
|
6
6
|
import type { SaveFunction } from '../interfaces/SaveFunction.mjs';
|
|
7
7
|
import type { DeviceId } from '../interfaces/SyncTypes.mjs';
|
|
8
8
|
/**
|
|
@@ -10,7 +10,7 @@ import type { DeviceId } from '../interfaces/SyncTypes.mjs';
|
|
|
10
10
|
*/
|
|
11
11
|
declare class PersistentStorageManager {
|
|
12
12
|
private mediator;
|
|
13
|
-
private readonly
|
|
13
|
+
private readonly passwordExtraDict;
|
|
14
14
|
private readonly favaMeta;
|
|
15
15
|
private readonly privateKey;
|
|
16
16
|
private readonly symmetricKey;
|
|
@@ -23,7 +23,7 @@ declare class PersistentStorageManager {
|
|
|
23
23
|
/**
|
|
24
24
|
* Constructs a new instance of PersistentStorageManager.
|
|
25
25
|
* @param mediator - The mediator for accessing other components.
|
|
26
|
-
* @param
|
|
26
|
+
* @param passwordExtraDict - Additional words to be used for password strength evaluation.
|
|
27
27
|
* @param favaMeta - Meta info containing at least a unique identifier for this device.
|
|
28
28
|
* @param privateKey - The private key used for cryptographic operations.
|
|
29
29
|
* @param symmetricKey - The symmetric key used for cryptographic operations.
|
|
@@ -32,7 +32,7 @@ declare class PersistentStorageManager {
|
|
|
32
32
|
* @param salt - The salt used for key derivation.
|
|
33
33
|
* @param saveFunction - The function to save the data.
|
|
34
34
|
*/
|
|
35
|
-
constructor(mediator: TwoFaLibMediator,
|
|
35
|
+
constructor(mediator: TwoFaLibMediator, passwordExtraDict: PasswordExtraDict, favaMeta: FavaMeta, privateKey: PrivateKey, symmetricKey: SymmetricKey, encryptedPrivateKey: EncryptedPrivateKey, encryptedSymmetricKey: EncryptedSymmetricKey, salt: Salt, saveFunction?: SaveFunction | undefined);
|
|
36
36
|
private get cryptoLib();
|
|
37
37
|
private get vaultDataManager();
|
|
38
38
|
private get syncManager();
|
|
@@ -46,7 +46,7 @@ declare class PersistentStorageManager {
|
|
|
46
46
|
getEncryptedVaultState(key?: SymmetricKey, forDeviceId?: DeviceId): Promise<EncryptedVaultStateString>;
|
|
47
47
|
/**
|
|
48
48
|
* Creates a partially encrypted representation of all data, except for
|
|
49
|
-
* the
|
|
49
|
+
* the password, that is needed to load the library. This can be used
|
|
50
50
|
* for secure storage of the library's data.
|
|
51
51
|
* @returns A promise that resolves with a json encoded string of
|
|
52
52
|
* the partially encrypted library's data.
|
|
@@ -67,19 +67,19 @@ declare class PersistentStorageManager {
|
|
|
67
67
|
*/
|
|
68
68
|
private performSave;
|
|
69
69
|
/**
|
|
70
|
-
* Validates the provided
|
|
70
|
+
* Validates the provided password against the current library password.
|
|
71
71
|
* @param salt - The salt used for key derivation.
|
|
72
|
-
* @param
|
|
73
|
-
* @returns A promise that resolves with a boolean indicating whether the
|
|
72
|
+
* @param password - The password to validate.
|
|
73
|
+
* @returns A promise that resolves with a boolean indicating whether the password is valid.
|
|
74
74
|
*/
|
|
75
|
-
|
|
75
|
+
validatePassword(salt: Salt, password: Password): Promise<boolean>;
|
|
76
76
|
/**
|
|
77
|
-
* Changes the library's
|
|
78
|
-
* @param
|
|
79
|
-
* @param
|
|
80
|
-
* @returns A promise that resolves when the
|
|
81
|
-
* @throws {AuthenticationError} If the provided old
|
|
77
|
+
* Changes the library's password.
|
|
78
|
+
* @param oldPassword - The current password.
|
|
79
|
+
* @param newPassword - The new password to set.
|
|
80
|
+
* @returns A promise that resolves when the password change is complete.
|
|
81
|
+
* @throws {AuthenticationError} If the provided old password is incorrect.
|
|
82
82
|
*/
|
|
83
|
-
|
|
83
|
+
changePassword(oldPassword: Password, newPassword: Password): Promise<void>;
|
|
84
84
|
}
|
|
85
85
|
export default PersistentStorageManager;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AuthenticationError } from '../TwoFALibError.mjs';
|
|
2
2
|
import TwoFaLib from '../TwoFaLib.mjs';
|
|
3
|
-
import {
|
|
3
|
+
import { validatePasswordStrength } from '../utils/creationUtils.mjs';
|
|
4
4
|
/**
|
|
5
5
|
* Manages all storage of data that should be persistent.
|
|
6
6
|
*/
|
|
@@ -9,7 +9,7 @@ class PersistentStorageManager {
|
|
|
9
9
|
/**
|
|
10
10
|
* Constructs a new instance of PersistentStorageManager.
|
|
11
11
|
* @param mediator - The mediator for accessing other components.
|
|
12
|
-
* @param
|
|
12
|
+
* @param passwordExtraDict - Additional words to be used for password strength evaluation.
|
|
13
13
|
* @param favaMeta - Meta info containing at least a unique identifier for this device.
|
|
14
14
|
* @param privateKey - The private key used for cryptographic operations.
|
|
15
15
|
* @param symmetricKey - The symmetric key used for cryptographic operations.
|
|
@@ -18,9 +18,9 @@ class PersistentStorageManager {
|
|
|
18
18
|
* @param salt - The salt used for key derivation.
|
|
19
19
|
* @param saveFunction - The function to save the data.
|
|
20
20
|
*/
|
|
21
|
-
constructor(mediator,
|
|
21
|
+
constructor(mediator, passwordExtraDict, favaMeta, privateKey, symmetricKey, encryptedPrivateKey, encryptedSymmetricKey, salt, saveFunction) {
|
|
22
22
|
this.mediator = mediator;
|
|
23
|
-
this.
|
|
23
|
+
this.passwordExtraDict = passwordExtraDict;
|
|
24
24
|
this.favaMeta = favaMeta;
|
|
25
25
|
this.privateKey = privateKey;
|
|
26
26
|
this.symmetricKey = symmetricKey;
|
|
@@ -67,7 +67,7 @@ class PersistentStorageManager {
|
|
|
67
67
|
}
|
|
68
68
|
/**
|
|
69
69
|
* Creates a partially encrypted representation of all data, except for
|
|
70
|
-
* the
|
|
70
|
+
* the password, that is needed to load the library. This can be used
|
|
71
71
|
* for secure storage of the library's data.
|
|
72
72
|
* @returns A promise that resolves with a json encoded string of
|
|
73
73
|
* the partially encrypted library's data.
|
|
@@ -122,14 +122,14 @@ class PersistentStorageManager {
|
|
|
122
122
|
await this.saveFunction(lockedRepresentation);
|
|
123
123
|
}
|
|
124
124
|
/**
|
|
125
|
-
* Validates the provided
|
|
125
|
+
* Validates the provided password against the current library password.
|
|
126
126
|
* @param salt - The salt used for key derivation.
|
|
127
|
-
* @param
|
|
128
|
-
* @returns A promise that resolves with a boolean indicating whether the
|
|
127
|
+
* @param password - The password to validate.
|
|
128
|
+
* @returns A promise that resolves with a boolean indicating whether the password is valid.
|
|
129
129
|
*/
|
|
130
|
-
async
|
|
130
|
+
async validatePassword(salt, password) {
|
|
131
131
|
try {
|
|
132
|
-
await this.cryptoLib.decryptKeys(this.encryptedPrivateKey, this.encryptedSymmetricKey, salt,
|
|
132
|
+
await this.cryptoLib.decryptKeys(this.encryptedPrivateKey, this.encryptedSymmetricKey, salt, password);
|
|
133
133
|
return true;
|
|
134
134
|
}
|
|
135
135
|
catch {
|
|
@@ -137,18 +137,18 @@ class PersistentStorageManager {
|
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
139
|
/**
|
|
140
|
-
* Changes the library's
|
|
141
|
-
* @param
|
|
142
|
-
* @param
|
|
143
|
-
* @returns A promise that resolves when the
|
|
144
|
-
* @throws {AuthenticationError} If the provided old
|
|
140
|
+
* Changes the library's password.
|
|
141
|
+
* @param oldPassword - The current password.
|
|
142
|
+
* @param newPassword - The new password to set.
|
|
143
|
+
* @returns A promise that resolves when the password change is complete.
|
|
144
|
+
* @throws {AuthenticationError} If the provided old password is incorrect.
|
|
145
145
|
*/
|
|
146
|
-
async
|
|
147
|
-
await
|
|
148
|
-
const isValid = await this.
|
|
146
|
+
async changePassword(oldPassword, newPassword) {
|
|
147
|
+
await validatePasswordStrength(this.mediator.getComponent('libraryLoader'), this.passwordExtraDict, newPassword);
|
|
148
|
+
const isValid = await this.validatePassword(this.salt, oldPassword);
|
|
149
149
|
if (!isValid)
|
|
150
|
-
throw new AuthenticationError('Invalid old
|
|
151
|
-
const { encryptedPrivateKey: newEncryptedPrivateKey, encryptedSymmetricKey: newEncryptedSymmetricKey, } = await this.cryptoLib.encryptKeys(this.privateKey, this.symmetricKey, this.salt,
|
|
150
|
+
throw new AuthenticationError('Invalid old password');
|
|
151
|
+
const { encryptedPrivateKey: newEncryptedPrivateKey, encryptedSymmetricKey: newEncryptedSymmetricKey, } = await this.cryptoLib.encryptKeys(this.privateKey, this.symmetricKey, this.salt, newPassword);
|
|
152
152
|
this.encryptedPrivateKey = newEncryptedPrivateKey;
|
|
153
153
|
this.encryptedSymmetricKey = newEncryptedSymmetricKey;
|
|
154
154
|
await this.save();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type TwoFaLibMediator from '../TwoFaLibMediator.mjs';
|
|
2
|
-
import type {
|
|
2
|
+
import type { Password } from '../interfaces/CryptoLib.mjs';
|
|
3
3
|
import type { SaveFunction } from '../interfaces/SaveFunction.mjs';
|
|
4
4
|
/**
|
|
5
5
|
* Manages the public operations related to the vault storage
|
|
@@ -21,13 +21,13 @@ declare class StorageOperationsManager {
|
|
|
21
21
|
*/
|
|
22
22
|
forceSave(): Promise<void>;
|
|
23
23
|
/**
|
|
24
|
-
* Changes the library's
|
|
25
|
-
* @param
|
|
26
|
-
* @param
|
|
27
|
-
* @returns A promise that resolves when the
|
|
28
|
-
* @throws {AuthenticationError} If the provided old
|
|
24
|
+
* Changes the library's password.
|
|
25
|
+
* @param oldPassword - The current password.
|
|
26
|
+
* @param newPassword - The new password to set.
|
|
27
|
+
* @returns A promise that resolves when the password change is complete.
|
|
28
|
+
* @throws {AuthenticationError} If the provided old password is incorrect.
|
|
29
29
|
*/
|
|
30
|
-
|
|
30
|
+
changePassword(oldPassword: Password, newPassword: Password): Promise<void>;
|
|
31
31
|
/**
|
|
32
32
|
* Sets the save function for the library.
|
|
33
33
|
* @param saveFunction - The save function to set.
|
|
@@ -23,14 +23,14 @@ class StorageOperationsManager {
|
|
|
23
23
|
return this.persistentStorage.save();
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
26
|
-
* Changes the library's
|
|
27
|
-
* @param
|
|
28
|
-
* @param
|
|
29
|
-
* @returns A promise that resolves when the
|
|
30
|
-
* @throws {AuthenticationError} If the provided old
|
|
26
|
+
* Changes the library's password.
|
|
27
|
+
* @param oldPassword - The current password.
|
|
28
|
+
* @param newPassword - The new password to set.
|
|
29
|
+
* @returns A promise that resolves when the password change is complete.
|
|
30
|
+
* @throws {AuthenticationError} If the provided old password is incorrect.
|
|
31
31
|
*/
|
|
32
|
-
async
|
|
33
|
-
return this.persistentStorage.
|
|
32
|
+
async changePassword(oldPassword, newPassword) {
|
|
33
|
+
return this.persistentStorage.changePassword(oldPassword, newPassword);
|
|
34
34
|
}
|
|
35
35
|
/**
|
|
36
36
|
* Sets the save function for the library.
|
|
@@ -1,45 +1,45 @@
|
|
|
1
1
|
import type { ZxcvbnResult } from '@zxcvbn-ts/core';
|
|
2
2
|
import type { PlatformProviders } from '../interfaces/PlatformProviders.mjs';
|
|
3
|
-
import type {
|
|
3
|
+
import type { Password } from '../interfaces/CryptoLib.mjs';
|
|
4
4
|
import type { DeviceType } from '../interfaces/SyncTypes.mjs';
|
|
5
5
|
import TwoFaLib from '../TwoFaLib.mjs';
|
|
6
6
|
import LibraryLoader from '../subclasses/LibraryLoader.mjs';
|
|
7
7
|
import type { LockedRepresentationString } from '../interfaces/Vault.mjs';
|
|
8
|
-
import type {
|
|
8
|
+
import type { PasswordExtraDict } from '../interfaces/PasswordExtraDict.js';
|
|
9
9
|
import { SaveFunction } from '../interfaces/SaveFunction.mjs';
|
|
10
10
|
/**
|
|
11
|
-
* Evaluates the strength of a
|
|
11
|
+
* Evaluates the strength of a password.
|
|
12
12
|
* @param libraryLoader - An instance of LibraryLoader.
|
|
13
|
-
* @param
|
|
14
|
-
* @param
|
|
15
|
-
* @returns Promise resolving to the
|
|
13
|
+
* @param passwordExtraDict - Additional words to be used for password strength evaluation.
|
|
14
|
+
* @param password - The password to evaluate.
|
|
15
|
+
* @returns Promise resolving to the password strength result.
|
|
16
16
|
*/
|
|
17
|
-
export declare const
|
|
17
|
+
export declare const getPasswordStrength: (libraryLoader: LibraryLoader, passwordExtraDict: PasswordExtraDict, password: Password) => Promise<ZxcvbnResult>;
|
|
18
18
|
/**
|
|
19
|
-
* Validates the strength of a
|
|
19
|
+
* Validates the strength of a password.
|
|
20
20
|
* @param libraryLoader - An instance of LibraryLoader.
|
|
21
|
-
* @param
|
|
22
|
-
* @param
|
|
23
|
-
* @throws {InitializationError} If the
|
|
21
|
+
* @param passwordExtraDict - Additional words to be used for password strength evaluation.
|
|
22
|
+
* @param password - The password to validate.
|
|
23
|
+
* @throws {InitializationError} If the password is too weak.
|
|
24
24
|
*/
|
|
25
|
-
export declare const
|
|
25
|
+
export declare const validatePasswordStrength: (libraryLoader: LibraryLoader, passwordExtraDict: PasswordExtraDict, password: Password) => Promise<void>;
|
|
26
26
|
/**
|
|
27
27
|
* Returns utility functions useful in creating a new twoFaLib vault
|
|
28
28
|
* @param platformProviders - The platform-specific providers containing CryptoLib and other providers.
|
|
29
29
|
* @param deviceType - A unique identifier for this device type (e.g. 2fa-cli).
|
|
30
|
-
* @param
|
|
30
|
+
* @param passwordExtraDict - Additional words to be used for password strength evaluation.
|
|
31
31
|
* @param saveFunction - The function to save the data.
|
|
32
32
|
* @param serverUrl - The server URL for syncing.
|
|
33
|
-
* @returns An object with methods to evaluate
|
|
33
|
+
* @returns An object with methods to evaluate password strength and create a new TwoFaLib vault.
|
|
34
34
|
*/
|
|
35
|
-
export declare const getTwoFaLibVaultCreationUtils: (platformProviders: PlatformProviders, deviceType: DeviceType,
|
|
36
|
-
|
|
37
|
-
createNewTwoFaLibVault: (
|
|
35
|
+
export declare const getTwoFaLibVaultCreationUtils: (platformProviders: PlatformProviders, deviceType: DeviceType, passwordExtraDict: PasswordExtraDict, saveFunction?: SaveFunction, serverUrl?: string) => {
|
|
36
|
+
getPasswordStrength: (password: Password) => Promise<ZxcvbnResult>;
|
|
37
|
+
createNewTwoFaLibVault: (password: Password) => Promise<{
|
|
38
38
|
twoFaLib: TwoFaLib;
|
|
39
39
|
publicKey: import("../interfaces/CryptoLib.mjs").PublicKey;
|
|
40
40
|
encryptedPrivateKey: import("../interfaces/CryptoLib.mjs").EncryptedPrivateKey;
|
|
41
41
|
encryptedSymmetricKey: import("../interfaces/CryptoLib.mjs").EncryptedSymmetricKey;
|
|
42
42
|
salt: import("../interfaces/CryptoLib.mjs").Salt;
|
|
43
43
|
}>;
|
|
44
|
-
loadTwoFaLibFromLockedRepesentation: (lockedRepresentationString: LockedRepresentationString,
|
|
44
|
+
loadTwoFaLibFromLockedRepesentation: (lockedRepresentationString: LockedRepresentationString, password: Password) => Promise<TwoFaLib>;
|
|
45
45
|
};
|
|
@@ -3,15 +3,15 @@ import TwoFaLib from '../TwoFaLib.mjs';
|
|
|
3
3
|
import { InitializationError, TwoFALibError } from '../TwoFALibError.mjs';
|
|
4
4
|
import LibraryLoader from '../subclasses/LibraryLoader.mjs';
|
|
5
5
|
/**
|
|
6
|
-
* Evaluates the strength of a
|
|
6
|
+
* Evaluates the strength of a password.
|
|
7
7
|
* @param libraryLoader - An instance of LibraryLoader.
|
|
8
|
-
* @param
|
|
9
|
-
* @param
|
|
10
|
-
* @returns Promise resolving to the
|
|
8
|
+
* @param passwordExtraDict - Additional words to be used for password strength evaluation.
|
|
9
|
+
* @param password - The password to evaluate.
|
|
10
|
+
* @returns Promise resolving to the password strength result.
|
|
11
11
|
*/
|
|
12
|
-
export const
|
|
12
|
+
export const getPasswordStrength = async (libraryLoader, passwordExtraDict, password) => {
|
|
13
13
|
const zxcvbn = await libraryLoader.getZxcvbn();
|
|
14
|
-
return zxcvbn(
|
|
14
|
+
return zxcvbn(password, [
|
|
15
15
|
'twofactor',
|
|
16
16
|
'authentication',
|
|
17
17
|
'token',
|
|
@@ -34,20 +34,20 @@ export const getPassphraseStrength = async (libraryLoader, passphrase, passphras
|
|
|
34
34
|
'key',
|
|
35
35
|
'trust',
|
|
36
36
|
'secure',
|
|
37
|
-
...
|
|
37
|
+
...passwordExtraDict,
|
|
38
38
|
]);
|
|
39
39
|
};
|
|
40
40
|
/**
|
|
41
|
-
* Validates the strength of a
|
|
41
|
+
* Validates the strength of a password.
|
|
42
42
|
* @param libraryLoader - An instance of LibraryLoader.
|
|
43
|
-
* @param
|
|
44
|
-
* @param
|
|
45
|
-
* @throws {InitializationError} If the
|
|
43
|
+
* @param passwordExtraDict - Additional words to be used for password strength evaluation.
|
|
44
|
+
* @param password - The password to validate.
|
|
45
|
+
* @throws {InitializationError} If the password is too weak.
|
|
46
46
|
*/
|
|
47
|
-
export const
|
|
48
|
-
const
|
|
49
|
-
if (
|
|
50
|
-
throw new TwoFALibError('
|
|
47
|
+
export const validatePasswordStrength = async (libraryLoader, passwordExtraDict, password) => {
|
|
48
|
+
const passwordStrength = await getPasswordStrength(libraryLoader, passwordExtraDict, password);
|
|
49
|
+
if (passwordStrength.score < 3) {
|
|
50
|
+
throw new TwoFALibError('Password is too weak');
|
|
51
51
|
}
|
|
52
52
|
};
|
|
53
53
|
/**
|
|
@@ -55,18 +55,18 @@ export const validatePassphraseStrength = async (libraryLoader, passphrase, pass
|
|
|
55
55
|
* @param libraryLoader - An instance of LibraryLoader.
|
|
56
56
|
* @param deviceType - A unique identifier for the device type e.g. 2fa-cli.
|
|
57
57
|
* @param serverUrl - The server URL for syncing.
|
|
58
|
-
* @param
|
|
58
|
+
* @param passwordExtraDict - Additional words to be used for password strength evaluation.
|
|
59
59
|
* @param saveFunction - The function to save the data.
|
|
60
|
-
* @param
|
|
60
|
+
* @param password - The password to be used to encrypt the private key.
|
|
61
61
|
* @returns Promise resolving to an object containing the newly created TwoFaLib instance and related data.
|
|
62
62
|
*/
|
|
63
|
-
const createNewTwoFaLibVault = async (libraryLoader, deviceType, serverUrl,
|
|
63
|
+
const createNewTwoFaLibVault = async (libraryLoader, deviceType, serverUrl, passwordExtraDict, saveFunction, password) => {
|
|
64
64
|
const cryptoLib = libraryLoader.getCryptoLib();
|
|
65
65
|
const platformProviders = libraryLoader.getPlatformProviders();
|
|
66
|
-
const { publicKey, privateKey, symmetricKey, encryptedPrivateKey, encryptedSymmetricKey, salt, } = await cryptoLib.createKeys(
|
|
67
|
-
await
|
|
66
|
+
const { publicKey, privateKey, symmetricKey, encryptedPrivateKey, encryptedSymmetricKey, salt, } = await cryptoLib.createKeys(password);
|
|
67
|
+
await validatePasswordStrength(libraryLoader, passwordExtraDict, password);
|
|
68
68
|
const deviceId = genUuidV4();
|
|
69
|
-
const twoFaLib = new TwoFaLib(deviceType, platformProviders,
|
|
69
|
+
const twoFaLib = new TwoFaLib(deviceType, platformProviders, passwordExtraDict, privateKey, symmetricKey, encryptedPrivateKey, encryptedSymmetricKey, salt, publicKey, {
|
|
70
70
|
deviceId,
|
|
71
71
|
}, [], saveFunction, {
|
|
72
72
|
serverUrl,
|
|
@@ -85,14 +85,14 @@ const createNewTwoFaLibVault = async (libraryLoader, deviceType, serverUrl, pass
|
|
|
85
85
|
* Loads the library state from a previously locked representation.
|
|
86
86
|
* @param libraryLoader - An instance of LibraryLoader.
|
|
87
87
|
* @param deviceType - A unique identifier for this device type (e.g. 2fa-cli).
|
|
88
|
-
* @param
|
|
88
|
+
* @param passwordExtraDict - Additional words to be used for password strength evaluation.
|
|
89
89
|
* @param saveFunction - The function to save the data.
|
|
90
90
|
* @param lockedRepresentationString - The string representation of the locked library state representation.
|
|
91
|
-
* @param
|
|
91
|
+
* @param password - The password for decrypting the keys.
|
|
92
92
|
* @returns A promise that resolves when loading is complete.
|
|
93
93
|
* @throws {InitializationError} If loading fails due to invalid or corrupted data.
|
|
94
94
|
*/
|
|
95
|
-
const loadTwoFaLibFromLockedRepesentation = async (libraryLoader, deviceType,
|
|
95
|
+
const loadTwoFaLibFromLockedRepesentation = async (libraryLoader, deviceType, passwordExtraDict, saveFunction, lockedRepresentationString, password) => {
|
|
96
96
|
const cryptoLib = libraryLoader.getCryptoLib();
|
|
97
97
|
const platformProviders = libraryLoader.getPlatformProviders();
|
|
98
98
|
const lockedRepresentation = JSON.parse(lockedRepresentationString);
|
|
@@ -103,7 +103,7 @@ const loadTwoFaLibFromLockedRepesentation = async (libraryLoader, deviceType, pa
|
|
|
103
103
|
!lockedRepresentation.encryptedVaultState) {
|
|
104
104
|
throw new InitializationError('lockedRepresentation is incomplete or corrupted');
|
|
105
105
|
}
|
|
106
|
-
const { privateKey, symmetricKey, publicKey } = await cryptoLib.decryptKeys(lockedRepresentation.encryptedPrivateKey, lockedRepresentation.encryptedSymmetricKey, lockedRepresentation.salt,
|
|
106
|
+
const { privateKey, symmetricKey, publicKey } = await cryptoLib.decryptKeys(lockedRepresentation.encryptedPrivateKey, lockedRepresentation.encryptedSymmetricKey, lockedRepresentation.salt, password);
|
|
107
107
|
const vaultState = JSON.parse(await cryptoLib.decryptSymmetric(symmetricKey, lockedRepresentation.encryptedVaultState));
|
|
108
108
|
if (!vaultState ||
|
|
109
109
|
!vaultState.deviceId ||
|
|
@@ -111,7 +111,7 @@ const loadTwoFaLibFromLockedRepesentation = async (libraryLoader, deviceType, pa
|
|
|
111
111
|
!vaultState.sync?.devices) {
|
|
112
112
|
throw new InitializationError('encryptedVaultState is incomplete or corrupted');
|
|
113
113
|
}
|
|
114
|
-
return new TwoFaLib(deviceType, platformProviders,
|
|
114
|
+
return new TwoFaLib(deviceType, platformProviders, passwordExtraDict, privateKey, symmetricKey, lockedRepresentation.encryptedPrivateKey, lockedRepresentation.encryptedSymmetricKey, lockedRepresentation.salt, publicKey, {
|
|
115
115
|
deviceId: vaultState.deviceId,
|
|
116
116
|
deviceFriendlyName: vaultState.deviceFriendlyName,
|
|
117
117
|
}, vaultState.vault, saveFunction, vaultState.sync);
|
|
@@ -120,16 +120,16 @@ const loadTwoFaLibFromLockedRepesentation = async (libraryLoader, deviceType, pa
|
|
|
120
120
|
* Returns utility functions useful in creating a new twoFaLib vault
|
|
121
121
|
* @param platformProviders - The platform-specific providers containing CryptoLib and other providers.
|
|
122
122
|
* @param deviceType - A unique identifier for this device type (e.g. 2fa-cli).
|
|
123
|
-
* @param
|
|
123
|
+
* @param passwordExtraDict - Additional words to be used for password strength evaluation.
|
|
124
124
|
* @param saveFunction - The function to save the data.
|
|
125
125
|
* @param serverUrl - The server URL for syncing.
|
|
126
|
-
* @returns An object with methods to evaluate
|
|
126
|
+
* @returns An object with methods to evaluate password strength and create a new TwoFaLib vault.
|
|
127
127
|
*/
|
|
128
|
-
export const getTwoFaLibVaultCreationUtils = (platformProviders, deviceType,
|
|
128
|
+
export const getTwoFaLibVaultCreationUtils = (platformProviders, deviceType, passwordExtraDict, saveFunction, serverUrl) => {
|
|
129
129
|
const libraryLoader = new LibraryLoader(platformProviders);
|
|
130
130
|
return {
|
|
131
|
-
|
|
132
|
-
createNewTwoFaLibVault: createNewTwoFaLibVault.bind(null, libraryLoader, deviceType, serverUrl,
|
|
133
|
-
loadTwoFaLibFromLockedRepesentation: loadTwoFaLibFromLockedRepesentation.bind(null, libraryLoader, deviceType,
|
|
131
|
+
getPasswordStrength: getPasswordStrength.bind(null, libraryLoader, passwordExtraDict),
|
|
132
|
+
createNewTwoFaLibVault: createNewTwoFaLibVault.bind(null, libraryLoader, deviceType, serverUrl, passwordExtraDict, saveFunction),
|
|
133
|
+
loadTwoFaLibFromLockedRepesentation: loadTwoFaLibFromLockedRepesentation.bind(null, libraryLoader, deviceType, passwordExtraDict, saveFunction),
|
|
134
134
|
};
|
|
135
135
|
};
|
package/package.json
CHANGED
|
File without changes
|