favalib 0.0.7 → 0.0.9
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/CryptoProviders/browser/index.d.mts +1 -1
- package/build/CryptoProviders/node/index.d.mts +1 -1
- package/build/TwoFaLib.d.mts +14 -5
- package/build/TwoFaLib.mjs +21 -7
- package/build/interfaces/FavaMeta.d.mts +5 -0
- package/build/interfaces/FavaMeta.mjs +1 -0
- package/build/interfaces/SaveFunction.d.mts +1 -2
- package/build/interfaces/Vault.d.mts +2 -1
- package/build/main.d.mts +1 -1
- package/build/subclasses/PersistentStorageManager.d.mts +8 -8
- package/build/subclasses/PersistentStorageManager.mjs +6 -5
- package/build/subclasses/StorageOperationsManager.d.mts +7 -0
- package/build/subclasses/StorageOperationsManager.mjs +8 -0
- package/build/subclasses/SyncManager.d.mts +13 -4
- package/build/subclasses/SyncManager.mjs +31 -5
- package/build/utils/creationUtils.d.mts +1 -1
- package/build/utils/creationUtils.mjs +7 -2
- package/build/utils/exportImportUtils.mjs +1 -0
- package/build/utils/syncUtils.d.mts +1 -1
- package/package.json +8 -8
package/build/TwoFaLib.d.mts
CHANGED
|
@@ -1,27 +1,36 @@
|
|
|
1
1
|
import { TypedEventTarget } from 'typescript-event-target';
|
|
2
2
|
import type CryptoLib from './interfaces/CryptoLib.mjs';
|
|
3
3
|
import type { EncryptedPrivateKey, EncryptedSymmetricKey, PrivateKey, PublicKey, Salt, SymmetricKey } from './interfaces/CryptoLib.mjs';
|
|
4
|
-
import type { DeviceFriendlyName,
|
|
4
|
+
import type { DeviceFriendlyName, DeviceType } from './interfaces/SyncTypes.mjs';
|
|
5
5
|
import type { TwoFaLibEventMapEvents } from './interfaces/Events.mjs';
|
|
6
6
|
import type { PassphraseExtraDict } from './interfaces/PassphraseExtraDict.js';
|
|
7
7
|
import type { Vault, VaultSyncState } from './interfaces/Vault.mjs';
|
|
8
|
+
import type { SaveFunction } from './interfaces/SaveFunction.mjs';
|
|
9
|
+
import type { FavaMeta } from './interfaces/FavaMeta.mjs';
|
|
8
10
|
import SyncManager from './subclasses/SyncManager.mjs';
|
|
9
11
|
import ExportImportManager from './subclasses/ExportImportManager.mjs';
|
|
10
12
|
import VaultOperationsManager from './subclasses/VaultOperationsManager.mjs';
|
|
11
|
-
import SaveFunction from './interfaces/SaveFunction.mjs';
|
|
12
13
|
import StorageOperationsManager from './subclasses/StorageOperationsManager.mjs';
|
|
13
14
|
/**
|
|
14
15
|
* The Two-Factor Library, this is the main entry point.
|
|
15
16
|
*/
|
|
16
17
|
declare class TwoFaLib extends TypedEventTarget<TwoFaLibEventMapEvents> {
|
|
17
18
|
static readonly version = "0.0.1";
|
|
18
|
-
readonly
|
|
19
|
+
private readonly favaMeta;
|
|
19
20
|
readonly deviceType: DeviceType;
|
|
20
21
|
deviceFriendlyName: DeviceFriendlyName;
|
|
21
22
|
private mediator;
|
|
22
23
|
private readonly publicKey;
|
|
23
24
|
private readonly privateKey;
|
|
24
25
|
readonly ready: Promise<unknown>;
|
|
26
|
+
/**
|
|
27
|
+
* @returns The meta info for this device.
|
|
28
|
+
*/
|
|
29
|
+
get meta(): {
|
|
30
|
+
deviceId: import("./interfaces/SyncTypes.mjs").DeviceId;
|
|
31
|
+
deviceFriendlyName: DeviceFriendlyName;
|
|
32
|
+
deviceType: DeviceType;
|
|
33
|
+
};
|
|
25
34
|
/**
|
|
26
35
|
* Constructs a new instance of TwoFaLib. If a serverUrl is provided, the library will use it for its sync operations.
|
|
27
36
|
* @param deviceType - The identifier for this device type (e.g. 2fa-cli).
|
|
@@ -33,7 +42,7 @@ declare class TwoFaLib extends TypedEventTarget<TwoFaLibEventMapEvents> {
|
|
|
33
42
|
* @param encryptedSymmetricKey - The encrypted symmetric key
|
|
34
43
|
* @param salt - The salt used for key derivation.
|
|
35
44
|
* @param publicKey - The public key of the device.
|
|
36
|
-
* @param
|
|
45
|
+
* @param favaMeta - Meta info containing at least a unique identifier for this device.
|
|
37
46
|
* @param vault - The vault data (entries)
|
|
38
47
|
* @param saveFunction - The function to save the data.
|
|
39
48
|
* @param syncState - The state of the sync, includes the serverUrl
|
|
@@ -41,7 +50,7 @@ declare class TwoFaLib extends TypedEventTarget<TwoFaLibEventMapEvents> {
|
|
|
41
50
|
* @throws {InitializationError} If some parameter has an invalid value
|
|
42
51
|
* @throws {AuthenticationError} If the provided passphrase is incorrect.
|
|
43
52
|
*/
|
|
44
|
-
constructor(deviceType: DeviceType, cryptoLib: CryptoLib, passphraseExtraDict: PassphraseExtraDict, privateKey: PrivateKey, symmetricKey: SymmetricKey, encryptedPrivateKey: EncryptedPrivateKey, encryptedSymmetricKey: EncryptedSymmetricKey, salt: Salt, publicKey: PublicKey,
|
|
53
|
+
constructor(deviceType: DeviceType, cryptoLib: CryptoLib, passphraseExtraDict: PassphraseExtraDict, privateKey: PrivateKey, symmetricKey: SymmetricKey, encryptedPrivateKey: EncryptedPrivateKey, encryptedSymmetricKey: EncryptedSymmetricKey, salt: Salt, publicKey: PublicKey, favaMeta: FavaMeta, vault?: Vault, saveFunction?: SaveFunction, syncState?: VaultSyncState);
|
|
45
54
|
/**
|
|
46
55
|
* @returns The persistent storage manager instance which can be used to store data.
|
|
47
56
|
*/
|
package/build/TwoFaLib.mjs
CHANGED
|
@@ -16,6 +16,16 @@ import StorageOperationsManager from './subclasses/StorageOperationsManager.mjs'
|
|
|
16
16
|
class TwoFaLib extends TypedEventTarget {
|
|
17
17
|
// TOOD: load this from package.json
|
|
18
18
|
static { this.version = '0.0.1'; }
|
|
19
|
+
/**
|
|
20
|
+
* @returns The meta info for this device.
|
|
21
|
+
*/
|
|
22
|
+
get meta() {
|
|
23
|
+
return {
|
|
24
|
+
deviceId: this.favaMeta.deviceId,
|
|
25
|
+
deviceFriendlyName: this.deviceFriendlyName ?? '',
|
|
26
|
+
deviceType: this.deviceType,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
19
29
|
/**
|
|
20
30
|
* Constructs a new instance of TwoFaLib. If a serverUrl is provided, the library will use it for its sync operations.
|
|
21
31
|
* @param deviceType - The identifier for this device type (e.g. 2fa-cli).
|
|
@@ -27,7 +37,7 @@ class TwoFaLib extends TypedEventTarget {
|
|
|
27
37
|
* @param encryptedSymmetricKey - The encrypted symmetric key
|
|
28
38
|
* @param salt - The salt used for key derivation.
|
|
29
39
|
* @param publicKey - The public key of the device.
|
|
30
|
-
* @param
|
|
40
|
+
* @param favaMeta - Meta info containing at least a unique identifier for this device.
|
|
31
41
|
* @param vault - The vault data (entries)
|
|
32
42
|
* @param saveFunction - The function to save the data.
|
|
33
43
|
* @param syncState - The state of the sync, includes the serverUrl
|
|
@@ -35,23 +45,27 @@ class TwoFaLib extends TypedEventTarget {
|
|
|
35
45
|
* @throws {InitializationError} If some parameter has an invalid value
|
|
36
46
|
* @throws {AuthenticationError} If the provided passphrase is incorrect.
|
|
37
47
|
*/
|
|
38
|
-
constructor(deviceType, cryptoLib, passphraseExtraDict, privateKey, symmetricKey, encryptedPrivateKey, encryptedSymmetricKey, salt, publicKey,
|
|
48
|
+
constructor(deviceType, cryptoLib, passphraseExtraDict, privateKey, symmetricKey, encryptedPrivateKey, encryptedSymmetricKey, salt, publicKey, favaMeta, vault, saveFunction, syncState) {
|
|
39
49
|
super();
|
|
40
50
|
this.deviceFriendlyName = '';
|
|
41
51
|
if (!deviceType) {
|
|
42
52
|
throw new InitializationError('Device type is required');
|
|
43
53
|
}
|
|
44
|
-
if (!deviceId) {
|
|
54
|
+
if (!favaMeta.deviceId) {
|
|
45
55
|
throw new InitializationError('Device id is required');
|
|
46
56
|
}
|
|
47
57
|
if (deviceType.length > 256) {
|
|
48
58
|
throw new InitializationError('Device type is too long, max 256 characters');
|
|
49
59
|
}
|
|
60
|
+
if (favaMeta.deviceFriendlyName &&
|
|
61
|
+
favaMeta.deviceFriendlyName.length > 256) {
|
|
62
|
+
throw new InitializationError('Device friendly name is too long, max 256 characters');
|
|
63
|
+
}
|
|
50
64
|
if (passphraseExtraDict?.length === 0) {
|
|
51
65
|
throw new InitializationError('Passphrase extra dictionary is required and must contain at least one element (eg phone)');
|
|
52
66
|
}
|
|
67
|
+
this.favaMeta = favaMeta;
|
|
53
68
|
this.deviceType = deviceType;
|
|
54
|
-
this.deviceId = deviceId;
|
|
55
69
|
this.publicKey = publicKey;
|
|
56
70
|
this.privateKey = privateKey;
|
|
57
71
|
this.mediator = new TwoFaLibMediator();
|
|
@@ -59,7 +73,7 @@ class TwoFaLib extends TypedEventTarget {
|
|
|
59
73
|
['libraryLoader', new LibraryLoader(cryptoLib)],
|
|
60
74
|
[
|
|
61
75
|
'persistentStorageManager',
|
|
62
|
-
new PersistentStorageManager(this.mediator, passphraseExtraDict,
|
|
76
|
+
new PersistentStorageManager(this.mediator, passphraseExtraDict, favaMeta, privateKey, symmetricKey, encryptedPrivateKey, encryptedSymmetricKey, salt, saveFunction),
|
|
63
77
|
],
|
|
64
78
|
['vaultDataManager', new VaultDataManager(this.mediator)],
|
|
65
79
|
['commandManager', new CommandManager(this.mediator)],
|
|
@@ -77,7 +91,7 @@ class TwoFaLib extends TypedEventTarget {
|
|
|
77
91
|
}
|
|
78
92
|
if (syncState?.serverUrl) {
|
|
79
93
|
// Initiate the syncManager
|
|
80
|
-
this.mediator.registerComponent('syncManager', new SyncManager(this.mediator, this.publicKey, this.privateKey, syncState, this.
|
|
94
|
+
this.mediator.registerComponent('syncManager', new SyncManager(this.mediator, this.publicKey, this.privateKey, this.meta, syncState, this.deviceType));
|
|
81
95
|
}
|
|
82
96
|
else {
|
|
83
97
|
// If no syncmanager we're ready now, otherwise the syncmanager is responsible for emitting the ready event
|
|
@@ -147,7 +161,7 @@ class TwoFaLib extends TypedEventTarget {
|
|
|
147
161
|
devices: [],
|
|
148
162
|
commandSendQueue: [],
|
|
149
163
|
};
|
|
150
|
-
const newSyncManager = new SyncManager(this.mediator, this.publicKey, this.privateKey, newSyncState, this.
|
|
164
|
+
const newSyncManager = new SyncManager(this.mediator, this.publicKey, this.privateKey, this.meta, newSyncState, this.deviceType);
|
|
151
165
|
const success = await new Promise((resolve) => {
|
|
152
166
|
this.addEventListener(TwoFaLibEvent.ConnectionToSyncServerStatusChanged, (event) => {
|
|
153
167
|
if (event.detail.newStatus === ConnectionStatus.CONNECTED) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,3 +1,2 @@
|
|
|
1
1
|
import type { LockedRepresentationString } from './Vault.mjs';
|
|
2
|
-
type SaveFunction = (newLockedRepresentationString: LockedRepresentationString) => Promise<void> | void;
|
|
3
|
-
export default SaveFunction;
|
|
2
|
+
export type SaveFunction = (newLockedRepresentationString: LockedRepresentationString) => Promise<void> | void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Tagged } from 'type-fest';
|
|
2
2
|
import type { Encrypted, EncryptedPrivateKey, EncryptedSymmetricKey, Salt } from './CryptoLib.mjs';
|
|
3
3
|
import type Entry from './Entry.mjs';
|
|
4
|
-
import { DeviceId, SyncDevice } from './SyncTypes.mjs';
|
|
4
|
+
import { DeviceFriendlyName, DeviceId, SyncDevice } from './SyncTypes.mjs';
|
|
5
5
|
import { SyncCommandFromClient } from 'favaserver/ClientMessage';
|
|
6
6
|
export type Vault = Entry[];
|
|
7
7
|
export type EncryptedVaultStateString = Encrypted<VaultStateString>;
|
|
@@ -24,6 +24,7 @@ export type VaultSyncStateWithServerUrl = Omit<VaultSyncState, 'serverUrl'> & {
|
|
|
24
24
|
};
|
|
25
25
|
export interface VaultState {
|
|
26
26
|
deviceId: DeviceId;
|
|
27
|
+
deviceFriendlyName?: DeviceFriendlyName;
|
|
27
28
|
vault: Vault;
|
|
28
29
|
sync: VaultSyncState;
|
|
29
30
|
}
|
package/build/main.d.mts
CHANGED
|
@@ -5,7 +5,7 @@ import type CryptoLib from './interfaces/CryptoLib.mjs';
|
|
|
5
5
|
import type { Encrypted, EncryptedPrivateKey, EncryptedSymmetricKey, EncryptedPublicKey, PrivateKey, SymmetricKey, PublicKey, Passphrase, Salt } from './interfaces/CryptoLib.mjs';
|
|
6
6
|
import type { PublicSyncDevice, DeviceId, DeviceType, DeviceFriendlyName } from './interfaces/SyncTypes.mjs';
|
|
7
7
|
import type { EncryptedVaultStateString, LockedRepresentationString } from './interfaces/Vault.mjs';
|
|
8
|
-
import type SaveFunction from './interfaces/SaveFunction.mjs';
|
|
8
|
+
import type { SaveFunction } from './interfaces/SaveFunction.mjs';
|
|
9
9
|
import { TwoFALibError, InitializationError, AuthenticationError, EntryNotFoundError, TokenGenerationError } from './TwoFALibError.mjs';
|
|
10
10
|
import { TwoFaLibEvent } from './TwoFaLibEvent.mjs';
|
|
11
11
|
import { getTwoFaLibVaultCreationUtils } from './utils/creationUtils.mjs';
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import type { EncryptedPrivateKey, EncryptedSymmetricKey, Passphrase, PrivateKey, Salt, SymmetricKey } from '../interfaces/CryptoLib.mjs';
|
|
2
|
-
import { EncryptedVaultStateString } from '../interfaces/Vault.mjs';
|
|
2
|
+
import { EncryptedVaultStateString, LockedRepresentationString } from '../interfaces/Vault.mjs';
|
|
3
3
|
import type TwoFaLibMediator from '../TwoFaLibMediator.mjs';
|
|
4
|
-
import type {
|
|
4
|
+
import type { FavaMeta } from '../interfaces/FavaMeta.mjs';
|
|
5
5
|
import type { PassphraseExtraDict } from '../interfaces/PassphraseExtraDict.js';
|
|
6
|
-
import SaveFunction from '../interfaces/SaveFunction.mjs';
|
|
6
|
+
import { SaveFunction } from '../interfaces/SaveFunction.mjs';
|
|
7
7
|
/**
|
|
8
8
|
* Manages all storage of data that should be persistent.
|
|
9
9
|
*/
|
|
10
10
|
declare class PersistentStorageManager {
|
|
11
11
|
private mediator;
|
|
12
12
|
private readonly passphraseExtraDict;
|
|
13
|
-
private readonly
|
|
13
|
+
private readonly favaMeta;
|
|
14
14
|
private readonly privateKey;
|
|
15
15
|
private readonly symmetricKey;
|
|
16
16
|
private encryptedPrivateKey;
|
|
@@ -23,7 +23,7 @@ declare class PersistentStorageManager {
|
|
|
23
23
|
* Constructs a new instance of PersistentStorageManager.
|
|
24
24
|
* @param mediator - The mediator for accessing other components.
|
|
25
25
|
* @param passphraseExtraDict - Additional words to be used for passphrase strength evaluation.
|
|
26
|
-
* @param
|
|
26
|
+
* @param favaMeta - Meta info containing at least a unique identifier for this device.
|
|
27
27
|
* @param privateKey - The private key used for cryptographic operations.
|
|
28
28
|
* @param symmetricKey - The symmetric key used for cryptographic operations.
|
|
29
29
|
* @param encryptedPrivateKey - The encrypted private key
|
|
@@ -31,7 +31,7 @@ declare class PersistentStorageManager {
|
|
|
31
31
|
* @param salt - The salt used for key derivation.
|
|
32
32
|
* @param saveFunction - The function to save the data.
|
|
33
33
|
*/
|
|
34
|
-
constructor(mediator: TwoFaLibMediator, passphraseExtraDict: PassphraseExtraDict,
|
|
34
|
+
constructor(mediator: TwoFaLibMediator, passphraseExtraDict: PassphraseExtraDict, favaMeta: FavaMeta, privateKey: PrivateKey, symmetricKey: SymmetricKey, encryptedPrivateKey: EncryptedPrivateKey, encryptedSymmetricKey: EncryptedSymmetricKey, salt: Salt, saveFunction?: SaveFunction | undefined);
|
|
35
35
|
private get cryptoLib();
|
|
36
36
|
private get vaultDataManager();
|
|
37
37
|
private get syncManager();
|
|
@@ -49,9 +49,9 @@ declare class PersistentStorageManager {
|
|
|
49
49
|
* @returns A promise that resolves with a json encoded string of
|
|
50
50
|
* the partially encrypted library's data.
|
|
51
51
|
*/
|
|
52
|
-
|
|
52
|
+
getLockedRepresentation(): Promise<LockedRepresentationString>;
|
|
53
53
|
/**
|
|
54
|
-
* Sets the save function for the library.
|
|
54
|
+
* Sets the save function for the library.
|
|
55
55
|
* @param saveFunction - The save function to set.
|
|
56
56
|
*/
|
|
57
57
|
setSaveFunction(saveFunction: SaveFunction): void;
|
|
@@ -10,7 +10,7 @@ class PersistentStorageManager {
|
|
|
10
10
|
* Constructs a new instance of PersistentStorageManager.
|
|
11
11
|
* @param mediator - The mediator for accessing other components.
|
|
12
12
|
* @param passphraseExtraDict - Additional words to be used for passphrase strength evaluation.
|
|
13
|
-
* @param
|
|
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.
|
|
16
16
|
* @param encryptedPrivateKey - The encrypted private key
|
|
@@ -18,10 +18,10 @@ 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, passphraseExtraDict,
|
|
21
|
+
constructor(mediator, passphraseExtraDict, favaMeta, privateKey, symmetricKey, encryptedPrivateKey, encryptedSymmetricKey, salt, saveFunction) {
|
|
22
22
|
this.mediator = mediator;
|
|
23
23
|
this.passphraseExtraDict = passphraseExtraDict;
|
|
24
|
-
this.
|
|
24
|
+
this.favaMeta = favaMeta;
|
|
25
25
|
this.privateKey = privateKey;
|
|
26
26
|
this.symmetricKey = symmetricKey;
|
|
27
27
|
this.encryptedPrivateKey = encryptedPrivateKey;
|
|
@@ -52,7 +52,8 @@ class PersistentStorageManager {
|
|
|
52
52
|
const vault = this.vaultDataManager.getAllEntries();
|
|
53
53
|
const vaultState = {
|
|
54
54
|
vault,
|
|
55
|
-
deviceId: this.deviceId,
|
|
55
|
+
deviceId: this.favaMeta.deviceId,
|
|
56
|
+
deviceFriendlyName: this.favaMeta.deviceFriendlyName,
|
|
56
57
|
sync: {
|
|
57
58
|
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
58
59
|
devices: this.syncManager ? this.syncManager['syncDevices'] : [],
|
|
@@ -82,7 +83,7 @@ class PersistentStorageManager {
|
|
|
82
83
|
return JSON.stringify(lockedRepresentation);
|
|
83
84
|
}
|
|
84
85
|
/**
|
|
85
|
-
* Sets the save function for the library.
|
|
86
|
+
* Sets the save function for the library.
|
|
86
87
|
* @param saveFunction - The save function to set.
|
|
87
88
|
*/
|
|
88
89
|
setSaveFunction(saveFunction) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type TwoFaLibMediator from '../TwoFaLibMediator.mjs';
|
|
2
2
|
import type { Passphrase } from '../interfaces/CryptoLib.mjs';
|
|
3
|
+
import type { SaveFunction } from '../interfaces/SaveFunction.mjs';
|
|
3
4
|
/**
|
|
4
5
|
* Manages the public operations related to the vault storage
|
|
5
6
|
*/
|
|
@@ -16,6 +17,7 @@ declare class StorageOperationsManager {
|
|
|
16
17
|
get persistentStorage(): import("./PersistentStorageManager.mjs").default;
|
|
17
18
|
/**
|
|
18
19
|
* Forces a save.
|
|
20
|
+
* @returns void
|
|
19
21
|
*/
|
|
20
22
|
forceSave(): Promise<void>;
|
|
21
23
|
/**
|
|
@@ -26,5 +28,10 @@ declare class StorageOperationsManager {
|
|
|
26
28
|
* @throws {AuthenticationError} If the provided old passphrase is incorrect.
|
|
27
29
|
*/
|
|
28
30
|
changePassphrase(oldPassphrase: Passphrase, newPassphrase: Passphrase): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Sets the save function for the library.
|
|
33
|
+
* @param saveFunction - The save function to set.
|
|
34
|
+
*/
|
|
35
|
+
setSaveFunction(saveFunction: SaveFunction): void;
|
|
29
36
|
}
|
|
30
37
|
export default StorageOperationsManager;
|
|
@@ -17,6 +17,7 @@ class StorageOperationsManager {
|
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
19
|
* Forces a save.
|
|
20
|
+
* @returns void
|
|
20
21
|
*/
|
|
21
22
|
async forceSave() {
|
|
22
23
|
return this.persistentStorage.save();
|
|
@@ -31,5 +32,12 @@ class StorageOperationsManager {
|
|
|
31
32
|
async changePassphrase(oldPassphrase, newPassphrase) {
|
|
32
33
|
return this.persistentStorage.changePassphrase(oldPassphrase, newPassphrase);
|
|
33
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Sets the save function for the library.
|
|
37
|
+
* @param saveFunction - The save function to set.
|
|
38
|
+
*/
|
|
39
|
+
setSaveFunction(saveFunction) {
|
|
40
|
+
this.persistentStorage.setSaveFunction(saveFunction);
|
|
41
|
+
}
|
|
34
42
|
}
|
|
35
43
|
export default StorageOperationsManager;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { SyncDevice,
|
|
1
|
+
import { SyncDevice, PublicSyncDevice, DeviceFriendlyName, DeviceType } from '../interfaces/SyncTypes.mjs';
|
|
2
2
|
import type { PrivateKey, PublicKey } from '../interfaces/CryptoLib.mjs';
|
|
3
3
|
import type Command from '../Command/BaseCommand.mjs';
|
|
4
4
|
import type TwoFaLibMediator from '../TwoFaLibMediator.mjs';
|
|
5
5
|
import { VaultSyncStateWithServerUrl } from '../interfaces/Vault.mjs';
|
|
6
|
+
import type { FavaMeta } from '../interfaces/FavaMeta.mjs';
|
|
6
7
|
import { SyncCommandFromServer } from 'favaserver/ServerMessage';
|
|
7
8
|
import { SyncCommandFromClient } from 'favaserver/ClientMessage';
|
|
8
9
|
export declare enum ConnectionStatus {
|
|
@@ -18,18 +19,20 @@ declare class SyncManager {
|
|
|
18
19
|
private readonly mediator;
|
|
19
20
|
private readonly publicKey;
|
|
20
21
|
private readonly privateKey;
|
|
22
|
+
private readonly favaMeta;
|
|
23
|
+
private readonly deviceType;
|
|
21
24
|
private ws?;
|
|
22
25
|
private activeAddDeviceFlow?;
|
|
23
26
|
private readonly reconnectInterval;
|
|
24
27
|
readonly serverUrl: string;
|
|
25
28
|
private syncDevices;
|
|
26
|
-
deviceId: DeviceId;
|
|
27
29
|
private readyEventEmitted;
|
|
28
30
|
private commandSendQueue;
|
|
29
31
|
private reconnectTimeout?;
|
|
30
32
|
private terminateTimeout?;
|
|
31
33
|
private connectionFailedTimeout?;
|
|
32
34
|
private shouldReconnect;
|
|
35
|
+
private get deviceId();
|
|
33
36
|
/**
|
|
34
37
|
* Public getter for the command send queue.
|
|
35
38
|
* @returns The command send queue.
|
|
@@ -45,11 +48,12 @@ declare class SyncManager {
|
|
|
45
48
|
* @param mediator - The mediator for accessing other components.
|
|
46
49
|
* @param publicKey - The public key of the device.
|
|
47
50
|
* @param privateKey - The private key of the device.
|
|
51
|
+
* @param favaMeta - Meta info containing at least a unique identifier for this device.
|
|
48
52
|
* @param syncState - The state of the sync.
|
|
49
|
-
* @param
|
|
53
|
+
* @param deviceType - The identifier for this device type (e.g. 2fa-cli).
|
|
50
54
|
* @throws {InitializationError} If initialization fails (e.g., if the server URL is invalid).
|
|
51
55
|
*/
|
|
52
|
-
constructor(mediator: TwoFaLibMediator, publicKey: PublicKey, privateKey: PrivateKey, syncState: VaultSyncStateWithServerUrl,
|
|
56
|
+
constructor(mediator: TwoFaLibMediator, publicKey: PublicKey, privateKey: PrivateKey, favaMeta: FavaMeta, syncState: VaultSyncStateWithServerUrl, deviceType: DeviceType);
|
|
53
57
|
private get libraryLoader();
|
|
54
58
|
private get cryptoLib();
|
|
55
59
|
private get persistentStorageManager();
|
|
@@ -173,6 +177,11 @@ declare class SyncManager {
|
|
|
173
177
|
* Requests a resilver of the vault
|
|
174
178
|
*/
|
|
175
179
|
requestResilver(): void;
|
|
180
|
+
/**
|
|
181
|
+
* Change the meta of the current device, allows setting a friendly name
|
|
182
|
+
* @param deviceFriendlyName Human readable name for the device
|
|
183
|
+
*/
|
|
184
|
+
setDeviceFriendlyName(deviceFriendlyName: DeviceFriendlyName): Promise<void>;
|
|
176
185
|
/**
|
|
177
186
|
* Function to call when the server connection should be closed
|
|
178
187
|
*/
|
|
@@ -4,6 +4,7 @@ import { TwoFaLibEvent } from '../TwoFaLibEvent.mjs';
|
|
|
4
4
|
import { decodeInitiatorData, jsonToUint8Array } from '../utils/syncUtils.mjs';
|
|
5
5
|
import { InitializationError, SyncAddDeviceFlowConflictError, SyncError, SyncInWrongStateError, SyncNoServerConnectionError, TwoFALibError, } from '../TwoFALibError.mjs';
|
|
6
6
|
import AddSyncDeviceCommand from '../Command/commands/AddSyncDeviceCommand.mjs';
|
|
7
|
+
import ChangeSyncDeviceMetaCommand from '../Command/commands/ChangeSyncDeviceMetaCommand.mjs';
|
|
7
8
|
const IN_TESTING = process.env.NODE_ENV === 'test';
|
|
8
9
|
const IN_DEV = process.env.NODE_ENV === 'development';
|
|
9
10
|
export var ConnectionStatus;
|
|
@@ -22,6 +23,9 @@ const generateNonCryptographicRandomString = () => {
|
|
|
22
23
|
* Manages synchronization of 2FA devices and communication with the server.
|
|
23
24
|
*/
|
|
24
25
|
class SyncManager {
|
|
26
|
+
get deviceId() {
|
|
27
|
+
return this.favaMeta.deviceId;
|
|
28
|
+
}
|
|
25
29
|
/**
|
|
26
30
|
* Public getter for the command send queue.
|
|
27
31
|
* @returns The command send queue.
|
|
@@ -46,14 +50,17 @@ class SyncManager {
|
|
|
46
50
|
* @param mediator - The mediator for accessing other components.
|
|
47
51
|
* @param publicKey - The public key of the device.
|
|
48
52
|
* @param privateKey - The private key of the device.
|
|
53
|
+
* @param favaMeta - Meta info containing at least a unique identifier for this device.
|
|
49
54
|
* @param syncState - The state of the sync.
|
|
50
|
-
* @param
|
|
55
|
+
* @param deviceType - The identifier for this device type (e.g. 2fa-cli).
|
|
51
56
|
* @throws {InitializationError} If initialization fails (e.g., if the server URL is invalid).
|
|
52
57
|
*/
|
|
53
|
-
constructor(mediator, publicKey, privateKey, syncState,
|
|
58
|
+
constructor(mediator, publicKey, privateKey, favaMeta, syncState, deviceType) {
|
|
54
59
|
this.mediator = mediator;
|
|
55
60
|
this.publicKey = publicKey;
|
|
56
61
|
this.privateKey = privateKey;
|
|
62
|
+
this.favaMeta = favaMeta;
|
|
63
|
+
this.deviceType = deviceType;
|
|
57
64
|
this.reconnectInterval = IN_TESTING ? 100 : 5000; // 5 seconds
|
|
58
65
|
this.readyEventEmitted = false;
|
|
59
66
|
this.commandSendQueue = [];
|
|
@@ -64,14 +71,13 @@ class SyncManager {
|
|
|
64
71
|
throw new InitializationError('Invalid server URL, protocol must be wss');
|
|
65
72
|
}
|
|
66
73
|
}
|
|
67
|
-
this.deviceId = deviceId;
|
|
68
74
|
this.syncDevices = devices;
|
|
69
75
|
this.commandSendQueue = commandSendQueue;
|
|
70
76
|
this.serverUrl = serverUrl;
|
|
71
77
|
this.initServerConnection();
|
|
72
78
|
// add ourselves to the list of syncdevices if we're missing
|
|
73
79
|
void this.addSyncDevice({
|
|
74
|
-
deviceId: deviceId,
|
|
80
|
+
deviceId: this.favaMeta.deviceId,
|
|
75
81
|
publicKey: this.publicKey,
|
|
76
82
|
}, false);
|
|
77
83
|
// if not yet connected after 2 tries, emit ready event so we can continue
|
|
@@ -132,7 +138,8 @@ class SyncManager {
|
|
|
132
138
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
133
139
|
const syncManager = this;
|
|
134
140
|
ws.addEventListener('error', (event) => {
|
|
135
|
-
|
|
141
|
+
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
142
|
+
syncManager.log('warning', `Error in websocket: ${event.toString()}`);
|
|
136
143
|
});
|
|
137
144
|
ws.addEventListener('message', function message(message) {
|
|
138
145
|
try {
|
|
@@ -622,6 +629,25 @@ class SyncManager {
|
|
|
622
629
|
deviceIds: this.syncDevices.map((d) => d.deviceId),
|
|
623
630
|
});
|
|
624
631
|
}
|
|
632
|
+
/**
|
|
633
|
+
* Change the meta of the current device, allows setting a friendly name
|
|
634
|
+
* @param deviceFriendlyName Human readable name for the device
|
|
635
|
+
*/
|
|
636
|
+
async setDeviceFriendlyName(deviceFriendlyName) {
|
|
637
|
+
if (deviceFriendlyName.length > 256) {
|
|
638
|
+
throw new TwoFALibError('Device friendly name is too long, max 256 characters');
|
|
639
|
+
}
|
|
640
|
+
if (deviceFriendlyName.length < 1) {
|
|
641
|
+
throw new TwoFALibError('Device friendly name is too short, min 1 character');
|
|
642
|
+
}
|
|
643
|
+
this.favaMeta.deviceFriendlyName = deviceFriendlyName;
|
|
644
|
+
const newMeta = {
|
|
645
|
+
deviceId: this.deviceId,
|
|
646
|
+
newMeta: { deviceType: this.deviceType, deviceFriendlyName },
|
|
647
|
+
};
|
|
648
|
+
const command = ChangeSyncDeviceMetaCommand.create(newMeta);
|
|
649
|
+
await this.commandManager.execute(command);
|
|
650
|
+
}
|
|
625
651
|
/**
|
|
626
652
|
* Function to call when the server connection should be closed
|
|
627
653
|
*/
|
|
@@ -6,7 +6,7 @@ import TwoFaLib from '../TwoFaLib.mjs';
|
|
|
6
6
|
import LibraryLoader from '../subclasses/LibraryLoader.mjs';
|
|
7
7
|
import type { LockedRepresentationString } from '../interfaces/Vault.mjs';
|
|
8
8
|
import type { PassphraseExtraDict } from '../interfaces/PassphraseExtraDict.js';
|
|
9
|
-
import SaveFunction from '../interfaces/SaveFunction.mjs';
|
|
9
|
+
import { SaveFunction } from '../interfaces/SaveFunction.mjs';
|
|
10
10
|
/**
|
|
11
11
|
* Evaluates the strength of a passphrase.
|
|
12
12
|
* @param libraryLoader - An instance of LibraryLoader.
|
|
@@ -65,7 +65,9 @@ const createNewTwoFaLibVault = async (libraryLoader, deviceType, serverUrl, pass
|
|
|
65
65
|
const { publicKey, privateKey, symmetricKey, encryptedPrivateKey, encryptedSymmetricKey, salt, } = await cryptoLib.createKeys(passphrase);
|
|
66
66
|
await validatePassphraseStrength(libraryLoader, passphrase, passphraseExtraDict);
|
|
67
67
|
const deviceId = genUuidV4();
|
|
68
|
-
const twoFaLib = new TwoFaLib(deviceType, cryptoLib, passphraseExtraDict, privateKey, symmetricKey, encryptedPrivateKey, encryptedSymmetricKey, salt, publicKey,
|
|
68
|
+
const twoFaLib = new TwoFaLib(deviceType, cryptoLib, passphraseExtraDict, privateKey, symmetricKey, encryptedPrivateKey, encryptedSymmetricKey, salt, publicKey, {
|
|
69
|
+
deviceId,
|
|
70
|
+
}, [], saveFunction, {
|
|
69
71
|
serverUrl,
|
|
70
72
|
devices: [],
|
|
71
73
|
commandSendQueue: [],
|
|
@@ -107,7 +109,10 @@ const loadTwoFaLibFromLockedRepesentation = async (libraryLoader, deviceType, pa
|
|
|
107
109
|
!vaultState.sync?.devices) {
|
|
108
110
|
throw new InitializationError('encryptedVaultState is incomplete or corrupted');
|
|
109
111
|
}
|
|
110
|
-
return new TwoFaLib(deviceType, cryptoLib, passphraseExtraDict, privateKey, symmetricKey, lockedRepresentation.encryptedPrivateKey, lockedRepresentation.encryptedSymmetricKey, lockedRepresentation.salt, publicKey,
|
|
112
|
+
return new TwoFaLib(deviceType, cryptoLib, passphraseExtraDict, privateKey, symmetricKey, lockedRepresentation.encryptedPrivateKey, lockedRepresentation.encryptedSymmetricKey, lockedRepresentation.salt, publicKey, {
|
|
113
|
+
deviceId: vaultState.deviceId,
|
|
114
|
+
deviceFriendlyName: vaultState.deviceFriendlyName,
|
|
115
|
+
}, vaultState.vault, saveFunction, vaultState.sync);
|
|
111
116
|
};
|
|
112
117
|
/**
|
|
113
118
|
* Returns utility functions useful in creating a new twoFaLib vault
|
|
@@ -162,6 +162,7 @@ export const processImportLines = async (lines, importFromUri) => {
|
|
|
162
162
|
* @returns A promise that resolves to the encrypted data.
|
|
163
163
|
*/
|
|
164
164
|
export const encryptExport = async (openPgpLib, data, password) => {
|
|
165
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
165
166
|
const encrypted = await openPgpLib.encrypt({
|
|
166
167
|
message: await openPgpLib.createMessage({ text: data }),
|
|
167
168
|
passwords: [password],
|
|
@@ -17,7 +17,7 @@ export declare const decodeInitiatorData: (initiatorData: string | Uint8Array |
|
|
|
17
17
|
* @param jsonObj - The JSONified Uint8Array to convert.
|
|
18
18
|
* @returns A Uint8Array containing the values of the JSONified Uint8Array.
|
|
19
19
|
*/
|
|
20
|
-
export declare const jsonifiedUint8ArraytoUint8Array: (jsonObj: Record<string, number>) => Uint8Array
|
|
20
|
+
export declare const jsonifiedUint8ArraytoUint8Array: (jsonObj: Record<string, number>) => Uint8Array<ArrayBuffer>;
|
|
21
21
|
/**
|
|
22
22
|
* Converts a JSON object to a record of Uint8Arrays.
|
|
23
23
|
* @param jsonObj - The JSON object to convert.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "favalib",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.9",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
"@types/qrcode": "^1.5.5",
|
|
29
29
|
"@types/uuid": "^10.0.0",
|
|
30
30
|
"@types/whatwg-url": "^13.0.0",
|
|
31
|
-
"@vitest/coverage-v8": "^3.1.
|
|
32
|
-
"eslint": "^9.
|
|
33
|
-
"type-fest": "^4.
|
|
34
|
-
"vitest": "^3.1.
|
|
31
|
+
"@vitest/coverage-v8": "^3.1.4",
|
|
32
|
+
"eslint": "^9.27.0",
|
|
33
|
+
"type-fest": "^4.41.0",
|
|
34
|
+
"vitest": "^3.1.4",
|
|
35
35
|
"vitest-websocket-mock": "^0.5.0"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
@@ -43,15 +43,15 @@
|
|
|
43
43
|
"jpake-ts": "^1.0.1",
|
|
44
44
|
"jsqr": "^1.4.0",
|
|
45
45
|
"node-forge": "^1.3.1",
|
|
46
|
-
"openpgp": "^6.1.
|
|
46
|
+
"openpgp": "^6.1.1",
|
|
47
47
|
"qrcode": "^1.5.4",
|
|
48
48
|
"totp-generator": "^1.0.0",
|
|
49
49
|
"typescript-event-target": "^1.1.1",
|
|
50
50
|
"uint8array-extras": "^1.4.0",
|
|
51
|
-
"unws": "^0.3.
|
|
51
|
+
"unws": "^0.3.2",
|
|
52
52
|
"uuid": "^11.1.0",
|
|
53
53
|
"whatwg-url": "^14.2.0",
|
|
54
|
-
"ws": "^8.18.
|
|
54
|
+
"ws": "^8.18.2"
|
|
55
55
|
},
|
|
56
56
|
"engines": {
|
|
57
57
|
"node": ">=20"
|