favalib 0.0.1
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/Command/BaseCommand.d.mts +65 -0
- package/build/Command/BaseCommand.mjs +54 -0
- package/build/Command/CommandQueue.d.mts +28 -0
- package/build/Command/CommandQueue.mjs +43 -0
- package/build/Command/commandConstructors.d.mts +11 -0
- package/build/Command/commandConstructors.mjs +11 -0
- package/build/Command/commands/AddEntryCommand.d.mts +31 -0
- package/build/Command/commands/AddEntryCommand.mjs +43 -0
- package/build/Command/commands/AddSyncDeviceCommand.d.mts +36 -0
- package/build/Command/commands/AddSyncDeviceCommand.mjs +42 -0
- package/build/Command/commands/DeleteEntryCommand.d.mts +35 -0
- package/build/Command/commands/DeleteEntryCommand.mjs +50 -0
- package/build/Command/commands/UpdateEntryCommand.d.mts +38 -0
- package/build/Command/commands/UpdateEntryCommand.mjs +51 -0
- package/build/CryptoProviders/browser/index.d.mts +73 -0
- package/build/CryptoProviders/browser/index.mjs +209 -0
- package/build/CryptoProviders/node/index.d.mts +62 -0
- package/build/CryptoProviders/node/index.mjs +189 -0
- package/build/TwoFALibError.d.mts +77 -0
- package/build/TwoFALibError.mjs +91 -0
- package/build/TwoFaLib.d.mts +95 -0
- package/build/TwoFaLib.mjs +180 -0
- package/build/TwoFaLibEvent.d.mts +8 -0
- package/build/TwoFaLibEvent.mjs +9 -0
- package/build/TwoFaLibMediator.d.mts +37 -0
- package/build/TwoFaLibMediator.mjs +58 -0
- package/build/interfaces/CommandTypes.d.mts +20 -0
- package/build/interfaces/CommandTypes.mjs +1 -0
- package/build/interfaces/CryptoLib.d.mts +113 -0
- package/build/interfaces/CryptoLib.mjs +1 -0
- package/build/interfaces/Entry.d.mts +33 -0
- package/build/interfaces/Entry.mjs +1 -0
- package/build/interfaces/Events.d.mts +22 -0
- package/build/interfaces/Events.mjs +1 -0
- package/build/interfaces/PassphraseExtraDict.d.ts +2 -0
- package/build/interfaces/PassphraseExtraDict.js +1 -0
- package/build/interfaces/SyncTypes.d.mts +45 -0
- package/build/interfaces/SyncTypes.mjs +1 -0
- package/build/interfaces/Vault.d.mts +30 -0
- package/build/interfaces/Vault.mjs +1 -0
- package/build/main.d.mts +12 -0
- package/build/main.mjs +5 -0
- package/build/subclasses/CommandManager.d.mts +46 -0
- package/build/subclasses/CommandManager.mjs +117 -0
- package/build/subclasses/ExportImportManager.d.mts +58 -0
- package/build/subclasses/ExportImportManager.mjs +105 -0
- package/build/subclasses/LibraryLoader.d.mts +56 -0
- package/build/subclasses/LibraryLoader.mjs +108 -0
- package/build/subclasses/PersistentStorageManager.d.mts +71 -0
- package/build/subclasses/PersistentStorageManager.mjs +127 -0
- package/build/subclasses/SyncManager.d.mts +161 -0
- package/build/subclasses/SyncManager.mjs +567 -0
- package/build/subclasses/VaultDataManager.d.mts +68 -0
- package/build/subclasses/VaultDataManager.mjs +114 -0
- package/build/subclasses/VaultOperationsManager.d.mts +91 -0
- package/build/subclasses/VaultOperationsManager.mjs +163 -0
- package/build/utils/constants.d.mts +2 -0
- package/build/utils/constants.mjs +1 -0
- package/build/utils/creationUtils.d.mts +43 -0
- package/build/utils/creationUtils.mjs +125 -0
- package/build/utils/exportImportUtils.d.mts +53 -0
- package/build/utils/exportImportUtils.mjs +185 -0
- package/build/utils/qrUtils.d.mts +25 -0
- package/build/utils/qrUtils.mjs +84 -0
- package/build/utils/syncUtils.d.mts +26 -0
- package/build/utils/syncUtils.mjs +78 -0
- package/package.json +56 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { AuthenticationError } from '../TwoFALibError.mjs';
|
|
2
|
+
import { TwoFaLibEvent } from '../TwoFaLibEvent.mjs';
|
|
3
|
+
import TwoFaLib from '../TwoFaLib.mjs';
|
|
4
|
+
import { validatePassphraseStrength } from '../utils/creationUtils.mjs';
|
|
5
|
+
/**
|
|
6
|
+
* Manages all storage of data that should be persistent.
|
|
7
|
+
*/
|
|
8
|
+
class PersistentStorageManager {
|
|
9
|
+
static { this.storageVersion = 1; }
|
|
10
|
+
/**
|
|
11
|
+
* Constructs a new instance of PersistentStorageManager.
|
|
12
|
+
* @param mediator - The mediator for accessing other components.
|
|
13
|
+
* @param passphraseExtraDict - Additional words to be used for passphrase strength evaluation.
|
|
14
|
+
* @param deviceId - The unique identifier of the device.
|
|
15
|
+
* @param privateKey - The private key used for cryptographic operations.
|
|
16
|
+
* @param symmetricKey - The symmetric key used for cryptographic operations.
|
|
17
|
+
* @param encryptedPrivateKey - The encrypted private key
|
|
18
|
+
* @param encryptedSymmetricKey - The encrypted symmetric key
|
|
19
|
+
* @param salt - The salt used for key derivation.
|
|
20
|
+
*/
|
|
21
|
+
constructor(mediator, passphraseExtraDict, deviceId, privateKey, symmetricKey, encryptedPrivateKey, encryptedSymmetricKey, salt) {
|
|
22
|
+
this.mediator = mediator;
|
|
23
|
+
this.passphraseExtraDict = passphraseExtraDict;
|
|
24
|
+
this.deviceId = deviceId;
|
|
25
|
+
this.privateKey = privateKey;
|
|
26
|
+
this.symmetricKey = symmetricKey;
|
|
27
|
+
this.encryptedPrivateKey = encryptedPrivateKey;
|
|
28
|
+
this.encryptedSymmetricKey = encryptedSymmetricKey;
|
|
29
|
+
this.salt = salt;
|
|
30
|
+
}
|
|
31
|
+
get cryptoLib() {
|
|
32
|
+
return this.mediator.getComponent('libraryLoader').getCryptoLib();
|
|
33
|
+
}
|
|
34
|
+
get vaultDataManager() {
|
|
35
|
+
return this.mediator.getComponent('vaultDataManager');
|
|
36
|
+
}
|
|
37
|
+
get syncManager() {
|
|
38
|
+
if (!this.mediator.componentIsInitialised('syncManager')) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
return this.mediator.getComponent('syncManager');
|
|
42
|
+
}
|
|
43
|
+
get dispatchLibEvent() {
|
|
44
|
+
return this.mediator.getComponent('dispatchLibEvent');
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Retrieves an encrypted representation of the library's current state.
|
|
48
|
+
* This can be used for secure storage or transmission of the library's data.
|
|
49
|
+
* @param key - The key to decrypt the locked representation with. If not provided the library's current symmetric key will be used.
|
|
50
|
+
* @returns A promise that resolves with a string representation of the locked state.
|
|
51
|
+
*/
|
|
52
|
+
async getEncryptedVaultState(key) {
|
|
53
|
+
const vault = this.vaultDataManager.getAllEntries();
|
|
54
|
+
const vaultState = {
|
|
55
|
+
vault,
|
|
56
|
+
deviceId: this.deviceId,
|
|
57
|
+
sync: {
|
|
58
|
+
devices: this.syncManager?.syncDevices ?? [],
|
|
59
|
+
serverUrl: this.syncManager?.serverUrl,
|
|
60
|
+
commandSendQueue: this.syncManager?.getCommandSendQueue() ?? [],
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
return await this.cryptoLib.encryptSymmetric(key ?? this.symmetricKey, JSON.stringify(vaultState));
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Creates a partially encrypted representation of all data, except for
|
|
67
|
+
* the passphrase, that is needed to load the library. This can be used
|
|
68
|
+
* for secure storage of the library's data.
|
|
69
|
+
* @returns A promise that resolves with a json encoded string of
|
|
70
|
+
* the partially encrypted library's data.
|
|
71
|
+
*/
|
|
72
|
+
async getLockedRepresentation() {
|
|
73
|
+
const encryptedVaultState = await this.getEncryptedVaultState();
|
|
74
|
+
const lockedRepresentation = {
|
|
75
|
+
libVersion: TwoFaLib.version,
|
|
76
|
+
storageVersion: PersistentStorageManager.storageVersion,
|
|
77
|
+
encryptedPrivateKey: this.encryptedPrivateKey,
|
|
78
|
+
encryptedSymmetricKey: this.encryptedSymmetricKey,
|
|
79
|
+
salt: this.salt,
|
|
80
|
+
encryptedVaultState: encryptedVaultState,
|
|
81
|
+
};
|
|
82
|
+
return JSON.stringify(lockedRepresentation);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Saves the current state of the library.
|
|
86
|
+
* @returns A promise that resolves when the save operation is complete.
|
|
87
|
+
*/
|
|
88
|
+
async save() {
|
|
89
|
+
const lockedRepresentation = await this.getLockedRepresentation();
|
|
90
|
+
this.dispatchLibEvent(TwoFaLibEvent.Changed, {
|
|
91
|
+
newLockedRepresentationString: lockedRepresentation,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Validates the provided passphrase against the current library passphrase.
|
|
96
|
+
* @param salt - The salt used for key derivation.
|
|
97
|
+
* @param passphrase - The passphrase to validate.
|
|
98
|
+
* @returns A promise that resolves with a boolean indicating whether the passphrase is valid.
|
|
99
|
+
*/
|
|
100
|
+
async validatePassphrase(salt, passphrase) {
|
|
101
|
+
try {
|
|
102
|
+
await this.cryptoLib.decryptKeys(this.encryptedPrivateKey, this.encryptedSymmetricKey, salt, passphrase);
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Changes the library's passphrase.
|
|
111
|
+
* @param oldPassphrase - The current passphrase.
|
|
112
|
+
* @param newPassphrase - The new passphrase to set.
|
|
113
|
+
* @returns A promise that resolves when the passphrase change is complete.
|
|
114
|
+
* @throws {AuthenticationError} If the provided old passphrase is incorrect.
|
|
115
|
+
*/
|
|
116
|
+
async changePassphrase(oldPassphrase, newPassphrase) {
|
|
117
|
+
await validatePassphraseStrength(this.mediator.getComponent('libraryLoader'), newPassphrase, this.passphraseExtraDict);
|
|
118
|
+
const isValid = await this.validatePassphrase(this.salt, oldPassphrase);
|
|
119
|
+
if (!isValid)
|
|
120
|
+
throw new AuthenticationError('Invalid old passphrase');
|
|
121
|
+
const { encryptedPrivateKey: newEncryptedPrivateKey, encryptedSymmetricKey: newEncryptedSymmetricKey, } = await this.cryptoLib.encryptKeys(this.privateKey, this.symmetricKey, this.salt, newPassphrase);
|
|
122
|
+
this.encryptedPrivateKey = newEncryptedPrivateKey;
|
|
123
|
+
this.encryptedSymmetricKey = newEncryptedSymmetricKey;
|
|
124
|
+
await this.save();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
export default PersistentStorageManager;
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { SyncDevice, DeviceId, DeviceType } from '../interfaces/SyncTypes.mjs';
|
|
2
|
+
import type { PrivateKey, PublicKey } from '../interfaces/CryptoLib.mjs';
|
|
3
|
+
import type Command from '../Command/BaseCommand.mjs';
|
|
4
|
+
import type TwoFaLibMediator from '../TwoFaLibMediator.mjs';
|
|
5
|
+
import { VaultSyncStateWithServerUrl } from '../interfaces/Vault.mjs';
|
|
6
|
+
import { SyncCommandFromServer } from 'favaserver/ServerMessage';
|
|
7
|
+
import { SyncCommandFromClient } from 'favaserver/ClientMessage';
|
|
8
|
+
import type { AddSyncDeviceData } from '../Command/commands/AddSyncDeviceCommand.mjs';
|
|
9
|
+
/**
|
|
10
|
+
* Manages synchronization of 2FA devices and communication with the server.
|
|
11
|
+
*/
|
|
12
|
+
declare class SyncManager {
|
|
13
|
+
private readonly mediator;
|
|
14
|
+
private readonly deviceType;
|
|
15
|
+
private readonly publicKey;
|
|
16
|
+
private readonly privateKey;
|
|
17
|
+
private ws?;
|
|
18
|
+
private activeAddDeviceFlow?;
|
|
19
|
+
private readonly reconnectInterval;
|
|
20
|
+
readonly serverUrl: string;
|
|
21
|
+
syncDevices: SyncDevice[];
|
|
22
|
+
deviceId: DeviceId;
|
|
23
|
+
private readyEventEmitted;
|
|
24
|
+
private commandSendQueue;
|
|
25
|
+
private reconnectTimeout?;
|
|
26
|
+
private shouldReconnect;
|
|
27
|
+
/**
|
|
28
|
+
* Public getter for the command send queue.
|
|
29
|
+
* @returns The command send queue.
|
|
30
|
+
*/
|
|
31
|
+
getCommandSendQueue(): SyncCommandFromClient[];
|
|
32
|
+
/**
|
|
33
|
+
* Creates an instance of SyncManager.
|
|
34
|
+
* @param mediator - The mediator for accessing other components.
|
|
35
|
+
* @param deviceType - The type of the device.
|
|
36
|
+
* @param publicKey - The public key of the device.
|
|
37
|
+
* @param privateKey - The private key of the device.
|
|
38
|
+
* @param syncState - The state of the sync.
|
|
39
|
+
* @param deviceId - The unique identifier of the device.
|
|
40
|
+
* @throws {InitializationError} If initialization fails (e.g., if the server URL is invalid).
|
|
41
|
+
*/
|
|
42
|
+
constructor(mediator: TwoFaLibMediator, deviceType: DeviceType, publicKey: PublicKey, privateKey: PrivateKey, syncState: VaultSyncStateWithServerUrl, deviceId: DeviceId);
|
|
43
|
+
private get libraryLoader();
|
|
44
|
+
private get cryptoLib();
|
|
45
|
+
private get persistentStorageManager();
|
|
46
|
+
private get commandManager();
|
|
47
|
+
private get dispatchLibEvent();
|
|
48
|
+
private get log();
|
|
49
|
+
/**
|
|
50
|
+
* @returns Whether an add device flow is currently active.
|
|
51
|
+
*/
|
|
52
|
+
get inAddDeviceFlow(): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* @returns Whether the WebSocket connection is open.
|
|
55
|
+
*/
|
|
56
|
+
get webSocketConnected(): boolean;
|
|
57
|
+
private getNonce;
|
|
58
|
+
private sendToServer;
|
|
59
|
+
/**
|
|
60
|
+
* Initializes the WebSocket connection to the server.
|
|
61
|
+
*/
|
|
62
|
+
initServerConnection(): void;
|
|
63
|
+
private handleWebSocketClose;
|
|
64
|
+
private handleServerMessage;
|
|
65
|
+
private attemptReconnect;
|
|
66
|
+
/**
|
|
67
|
+
* Initiates the process to add a new device.
|
|
68
|
+
* @param returnAs - An object specifying what should be returned:
|
|
69
|
+
* - `qr: boolean` - If `true`, the result will include a QR code string in the `qr` property.
|
|
70
|
+
* - `text: boolean` - If `true`, the result will include initiation data in the `text` property.
|
|
71
|
+
* @returns A promise that resolves to an object containing:
|
|
72
|
+
* - `qr`: If `returnAs.qr` is `true`, this will be a `string` containing the QR code; otherwise, `null`.
|
|
73
|
+
* - `text`: If `returnAs.text` is `true`, this will be an `InitiateAddDeviceFlowResult` object; otherwise, `null`.
|
|
74
|
+
* @throws {SyncAddDeviceFlowConflictError} If an add device flow is already active.
|
|
75
|
+
* @throws {SyncNoServerConnectionError} If there is no server connection.
|
|
76
|
+
*/
|
|
77
|
+
initiateAddDeviceFlow(returnAs: {
|
|
78
|
+
qr: true;
|
|
79
|
+
text: true;
|
|
80
|
+
}): Promise<{
|
|
81
|
+
qr: string;
|
|
82
|
+
text: string;
|
|
83
|
+
}>;
|
|
84
|
+
/**
|
|
85
|
+
* @inheritdoc
|
|
86
|
+
*/
|
|
87
|
+
initiateAddDeviceFlow(returnAs: {
|
|
88
|
+
qr: true;
|
|
89
|
+
text: false;
|
|
90
|
+
}): Promise<{
|
|
91
|
+
qr: string;
|
|
92
|
+
text: null;
|
|
93
|
+
}>;
|
|
94
|
+
/**
|
|
95
|
+
* @inheritdoc
|
|
96
|
+
*/
|
|
97
|
+
initiateAddDeviceFlow(returnAs: {
|
|
98
|
+
qr: false;
|
|
99
|
+
text: true;
|
|
100
|
+
}): Promise<{
|
|
101
|
+
qr: null;
|
|
102
|
+
text: string;
|
|
103
|
+
}>;
|
|
104
|
+
/**
|
|
105
|
+
* @inheritdoc
|
|
106
|
+
*/
|
|
107
|
+
initiateAddDeviceFlow(returnAs: {
|
|
108
|
+
qr: false;
|
|
109
|
+
text: false;
|
|
110
|
+
}): Promise<{
|
|
111
|
+
qr: null;
|
|
112
|
+
text: null;
|
|
113
|
+
}>;
|
|
114
|
+
/**
|
|
115
|
+
* Responds to an add device flow initiated by another device.
|
|
116
|
+
* @param initiatorData The data received from the initiating device.
|
|
117
|
+
* @param initiatorDataType The type of the initiatorData, determines how it should be decoded
|
|
118
|
+
* @throws {SyncNoServerConnectionError} If there is no server connection.
|
|
119
|
+
* @throws {SyncAddDeviceFlowConflictError} If an add device flow is already active.
|
|
120
|
+
* @throws {SyncError} If the initiator data is invalid.
|
|
121
|
+
*/
|
|
122
|
+
respondToAddDeviceFlow(initiatorData: string | Uint8Array | File, initiatorDataType: 'text' | 'qr'): Promise<void>;
|
|
123
|
+
private finishAddDeviceFlowKeyExchangeInitiator;
|
|
124
|
+
private finishAddDeviceFlowKeyExchangeResponder;
|
|
125
|
+
private sendInitialVaultData;
|
|
126
|
+
private importInitialVaultState;
|
|
127
|
+
/**
|
|
128
|
+
* Cancels the active add sync device flow.
|
|
129
|
+
* @throws {SyncNoServerConnectionError} If there is no server connection.
|
|
130
|
+
* @throws {SyncInWrongStateError} If there is no active add device flow.
|
|
131
|
+
*/
|
|
132
|
+
cancelAddSyncDevice(): void;
|
|
133
|
+
/**
|
|
134
|
+
* Sends a command to the server to synchronize with other devices.
|
|
135
|
+
* @param command - The command to be sent.
|
|
136
|
+
* @throws {SyncNoServerConnectionError} If there is no server connection.
|
|
137
|
+
*/
|
|
138
|
+
sendCommand(command: Command): Promise<void>;
|
|
139
|
+
private processCommandSendQueue;
|
|
140
|
+
/**
|
|
141
|
+
* Handles the confirmation that the sever succesfully received (some) send commands
|
|
142
|
+
* @param commandIds - The ids of the received commands
|
|
143
|
+
*/
|
|
144
|
+
private commandsSuccesfullyReceived;
|
|
145
|
+
/**
|
|
146
|
+
* Receives and processes commands from other devices.
|
|
147
|
+
* @param encryptedCommands - The commands
|
|
148
|
+
* @throws {CryptoError} If decryption fails.
|
|
149
|
+
*/
|
|
150
|
+
receiveCommands(encryptedCommands: SyncCommandFromServer[]): Promise<void>;
|
|
151
|
+
/**
|
|
152
|
+
* Add a sync device
|
|
153
|
+
* @param deviceInfo - The info about the device
|
|
154
|
+
*/
|
|
155
|
+
addSyncDevice(deviceInfo: AddSyncDeviceData): Promise<void>;
|
|
156
|
+
/**
|
|
157
|
+
* Function to call when the server connection should be closed
|
|
158
|
+
*/
|
|
159
|
+
closeServerConnection(): void;
|
|
160
|
+
}
|
|
161
|
+
export default SyncManager;
|