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,95 @@
|
|
|
1
|
+
import { TypedEventTarget } from 'typescript-event-target';
|
|
2
|
+
import type CryptoLib from './interfaces/CryptoLib.mjs';
|
|
3
|
+
import type { EncryptedPrivateKey, EncryptedSymmetricKey, Passphrase, PrivateKey, PublicKey, Salt, SymmetricKey } from './interfaces/CryptoLib.mjs';
|
|
4
|
+
import type { DeviceId, DeviceType } from './interfaces/SyncTypes.mjs';
|
|
5
|
+
import type { TwoFaLibEventMapEvents } from './interfaces/Events.mjs';
|
|
6
|
+
import type { PassphraseExtraDict } from './interfaces/PassphraseExtraDict.js';
|
|
7
|
+
import type { Vault, VaultSyncState } from './interfaces/Vault.mjs';
|
|
8
|
+
import SyncManager from './subclasses/SyncManager.mjs';
|
|
9
|
+
import ExportImportManager from './subclasses/ExportImportManager.mjs';
|
|
10
|
+
import VaultOperationsManager from './subclasses/VaultOperationsManager.mjs';
|
|
11
|
+
/**
|
|
12
|
+
* The Two-Factor Library, this is the main entry point.
|
|
13
|
+
*/
|
|
14
|
+
declare class TwoFaLib extends TypedEventTarget<TwoFaLibEventMapEvents> {
|
|
15
|
+
static readonly version = "0.0.1";
|
|
16
|
+
readonly deviceId: DeviceId;
|
|
17
|
+
readonly deviceType: DeviceType;
|
|
18
|
+
private mediator;
|
|
19
|
+
private readonly publicKey;
|
|
20
|
+
private readonly privateKey;
|
|
21
|
+
readonly ready: Promise<unknown>;
|
|
22
|
+
/**
|
|
23
|
+
* Constructs a new instance of TwoFaLib. If a serverUrl is provided, the library will use it for its sync operations.
|
|
24
|
+
* @param deviceType - A unique identifier for this device type (e.g. 2fa-cli).
|
|
25
|
+
* @param cryptoLib - An instance of CryptoLib that is compatible with the environment.
|
|
26
|
+
* @param passphraseExtraDict - Additional words to be used for passphrase strength evaluation.
|
|
27
|
+
* @param privateKey - The private key used for cryptographic operations.
|
|
28
|
+
* @param symmetricKey - The symmetric key used for cryptographic operations.
|
|
29
|
+
* @param encryptedPrivateKey - The encrypted private key
|
|
30
|
+
* @param encryptedSymmetricKey - The encrypted symmetric key
|
|
31
|
+
* @param salt - The salt used for key derivation.
|
|
32
|
+
* @param publicKey - The public key of the device.
|
|
33
|
+
* @param deviceId - A unique identifier for this device.
|
|
34
|
+
* @param vault - The vault data (entries)
|
|
35
|
+
* @param syncState - The state of the sync, includes the serverUrl
|
|
36
|
+
* @returns A promise that resolves when initialization is complete.
|
|
37
|
+
* @throws {InitializationError} If some parameter has an invalid value
|
|
38
|
+
* @throws {AuthenticationError} If the provided passphrase is incorrect.
|
|
39
|
+
*/
|
|
40
|
+
constructor(deviceType: DeviceType, cryptoLib: CryptoLib, passphraseExtraDict: PassphraseExtraDict, privateKey: PrivateKey, symmetricKey: SymmetricKey, encryptedPrivateKey: EncryptedPrivateKey, encryptedSymmetricKey: EncryptedSymmetricKey, salt: Salt, publicKey: PublicKey, deviceId: DeviceId, vault?: Vault, syncState?: VaultSyncState);
|
|
41
|
+
/**
|
|
42
|
+
* Gives access to vault operations.
|
|
43
|
+
* @returns The vault manager instance which can be used to perform operations on the vault.
|
|
44
|
+
*/
|
|
45
|
+
get vault(): VaultOperationsManager;
|
|
46
|
+
/**
|
|
47
|
+
* Gives access to export/import operations.
|
|
48
|
+
* @returns The export/import manager instance which can be used to export and import vaults.
|
|
49
|
+
*/
|
|
50
|
+
get exportImport(): ExportImportManager;
|
|
51
|
+
/**
|
|
52
|
+
* Gives access to sync operations.
|
|
53
|
+
* @returns The sync manager instance which can be used to sync the vault with a server or null if none was initialized.
|
|
54
|
+
*/
|
|
55
|
+
get sync(): SyncManager | null;
|
|
56
|
+
/**
|
|
57
|
+
* @returns The persistent storage manager instance which can be used to store data.
|
|
58
|
+
*/
|
|
59
|
+
private get persistentStorage();
|
|
60
|
+
/**
|
|
61
|
+
* Forces a save of the persistent storage.
|
|
62
|
+
*/
|
|
63
|
+
forceSave(): Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Changes the library's passphrase.
|
|
66
|
+
* @param oldPassphrase - The current passphrase.
|
|
67
|
+
* @param newPassphrase - The new passphrase to set.
|
|
68
|
+
* @returns A promise that resolves when the passphrase change is complete.
|
|
69
|
+
* @throws {AuthenticationError} If the provided old passphrase is incorrect.
|
|
70
|
+
*/
|
|
71
|
+
changePassphrase(oldPassphrase: Passphrase, newPassphrase: Passphrase): Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* Sets a server url, this will allow syncing with the server.
|
|
74
|
+
* @param serverUrl - The server url.
|
|
75
|
+
*/
|
|
76
|
+
setSyncServerUrl(serverUrl: string): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* Sets the sync state, this will initiate the sync manager instance.
|
|
79
|
+
* @param syncState - The state of the sync.
|
|
80
|
+
*/
|
|
81
|
+
private setSyncState;
|
|
82
|
+
/**
|
|
83
|
+
* Dispatches a library event.
|
|
84
|
+
* @param eventType - The type of the event to dispatch, uses the TwoFaLibEvent enum.
|
|
85
|
+
* @param data - Optional data to include with the event.
|
|
86
|
+
*/
|
|
87
|
+
private dispatchLibEvent;
|
|
88
|
+
/**
|
|
89
|
+
* Log a message
|
|
90
|
+
* @param severity - The severity of the message, either 'info' or 'warning'.
|
|
91
|
+
* @param message - The message to log.
|
|
92
|
+
*/
|
|
93
|
+
private log;
|
|
94
|
+
}
|
|
95
|
+
export default TwoFaLib;
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { TypedEventTarget } from 'typescript-event-target';
|
|
2
|
+
import TwoFaLibMediator from './TwoFaLibMediator.mjs';
|
|
3
|
+
import { TwoFaLibEvent } from './TwoFaLibEvent.mjs';
|
|
4
|
+
import { InitializationError } from './TwoFALibError.mjs';
|
|
5
|
+
import SyncManager from './subclasses/SyncManager.mjs';
|
|
6
|
+
import LibraryLoader from './subclasses/LibraryLoader.mjs';
|
|
7
|
+
import ExportImportManager from './subclasses/ExportImportManager.mjs';
|
|
8
|
+
import PersistentStorageManager from './subclasses/PersistentStorageManager.mjs';
|
|
9
|
+
import VaultDataManager from './subclasses/VaultDataManager.mjs';
|
|
10
|
+
import VaultOperationsManager from './subclasses/VaultOperationsManager.mjs';
|
|
11
|
+
import CommandManager from './subclasses/CommandManager.mjs';
|
|
12
|
+
/**
|
|
13
|
+
* The Two-Factor Library, this is the main entry point.
|
|
14
|
+
*/
|
|
15
|
+
class TwoFaLib extends TypedEventTarget {
|
|
16
|
+
// TOOD: load this from package.json
|
|
17
|
+
static { this.version = '0.0.1'; }
|
|
18
|
+
/**
|
|
19
|
+
* Constructs a new instance of TwoFaLib. If a serverUrl is provided, the library will use it for its sync operations.
|
|
20
|
+
* @param deviceType - A unique identifier for this device type (e.g. 2fa-cli).
|
|
21
|
+
* @param cryptoLib - An instance of CryptoLib that is compatible with the environment.
|
|
22
|
+
* @param passphraseExtraDict - Additional words to be used for passphrase strength evaluation.
|
|
23
|
+
* @param privateKey - The private key used for cryptographic operations.
|
|
24
|
+
* @param symmetricKey - The symmetric key used for cryptographic operations.
|
|
25
|
+
* @param encryptedPrivateKey - The encrypted private key
|
|
26
|
+
* @param encryptedSymmetricKey - The encrypted symmetric key
|
|
27
|
+
* @param salt - The salt used for key derivation.
|
|
28
|
+
* @param publicKey - The public key of the device.
|
|
29
|
+
* @param deviceId - A unique identifier for this device.
|
|
30
|
+
* @param vault - The vault data (entries)
|
|
31
|
+
* @param syncState - The state of the sync, includes the serverUrl
|
|
32
|
+
* @returns A promise that resolves when initialization is complete.
|
|
33
|
+
* @throws {InitializationError} If some parameter has an invalid value
|
|
34
|
+
* @throws {AuthenticationError} If the provided passphrase is incorrect.
|
|
35
|
+
*/
|
|
36
|
+
constructor(deviceType, cryptoLib, passphraseExtraDict, privateKey, symmetricKey, encryptedPrivateKey, encryptedSymmetricKey, salt, publicKey, deviceId, vault, syncState) {
|
|
37
|
+
super();
|
|
38
|
+
if (!deviceType) {
|
|
39
|
+
throw new InitializationError('Device type is required');
|
|
40
|
+
}
|
|
41
|
+
if (!deviceId) {
|
|
42
|
+
throw new InitializationError('Device id is required');
|
|
43
|
+
}
|
|
44
|
+
if (deviceType.length > 256) {
|
|
45
|
+
throw new InitializationError('Device type is too long, max 256 characters');
|
|
46
|
+
}
|
|
47
|
+
if (passphraseExtraDict?.length === 0) {
|
|
48
|
+
throw new InitializationError('Passphrase extra dictionary is required and must contain at least one element (eg phone)');
|
|
49
|
+
}
|
|
50
|
+
this.deviceType = deviceType;
|
|
51
|
+
this.deviceId = deviceId;
|
|
52
|
+
this.publicKey = publicKey;
|
|
53
|
+
this.privateKey = privateKey;
|
|
54
|
+
this.mediator = new TwoFaLibMediator();
|
|
55
|
+
this.mediator.registerComponents([
|
|
56
|
+
['libraryLoader', new LibraryLoader(cryptoLib)],
|
|
57
|
+
[
|
|
58
|
+
'persistentStorageManager',
|
|
59
|
+
new PersistentStorageManager(this.mediator, passphraseExtraDict, deviceId, privateKey, symmetricKey, encryptedPrivateKey, encryptedSymmetricKey, salt),
|
|
60
|
+
],
|
|
61
|
+
['vaultDataManager', new VaultDataManager(this.mediator)],
|
|
62
|
+
['commandManager', new CommandManager(this.mediator)],
|
|
63
|
+
['vaultOperationsManager', new VaultOperationsManager(this.mediator)],
|
|
64
|
+
[
|
|
65
|
+
'exportImportManager',
|
|
66
|
+
new ExportImportManager(this.mediator, passphraseExtraDict),
|
|
67
|
+
],
|
|
68
|
+
['dispatchLibEvent', this.dispatchLibEvent.bind(this)],
|
|
69
|
+
['log', this.log.bind(this)],
|
|
70
|
+
]);
|
|
71
|
+
if (vault) {
|
|
72
|
+
this.mediator.getComponent('vaultDataManager').replaceVault(vault);
|
|
73
|
+
}
|
|
74
|
+
if (syncState?.serverUrl) {
|
|
75
|
+
this.setSyncState(syncState);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
// If no syncmanager we're ready now, otherwise the syncmanager is responsible for emitting the ready event
|
|
79
|
+
// We do this with a delay of 1, so that there is time to add event listeners
|
|
80
|
+
setTimeout(() => this.dispatchLibEvent(TwoFaLibEvent.Ready), 1);
|
|
81
|
+
}
|
|
82
|
+
// populate the ready property
|
|
83
|
+
let setReady;
|
|
84
|
+
this.ready = new Promise((resolve) => {
|
|
85
|
+
setReady = resolve;
|
|
86
|
+
});
|
|
87
|
+
const handleReadyEvent = () => {
|
|
88
|
+
setReady();
|
|
89
|
+
this.removeEventListener(TwoFaLibEvent.Ready, handleReadyEvent);
|
|
90
|
+
};
|
|
91
|
+
this.addEventListener(TwoFaLibEvent.Ready, handleReadyEvent);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Gives access to vault operations.
|
|
95
|
+
* @returns The vault manager instance which can be used to perform operations on the vault.
|
|
96
|
+
*/
|
|
97
|
+
get vault() {
|
|
98
|
+
return this.mediator.getComponent('vaultOperationsManager');
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Gives access to export/import operations.
|
|
102
|
+
* @returns The export/import manager instance which can be used to export and import vaults.
|
|
103
|
+
*/
|
|
104
|
+
get exportImport() {
|
|
105
|
+
return this.mediator.getComponent('exportImportManager');
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Gives access to sync operations.
|
|
109
|
+
* @returns The sync manager instance which can be used to sync the vault with a server or null if none was initialized.
|
|
110
|
+
*/
|
|
111
|
+
get sync() {
|
|
112
|
+
if (!this.mediator.componentIsInitialised('syncManager')) {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
return this.mediator.getComponent('syncManager');
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* @returns The persistent storage manager instance which can be used to store data.
|
|
119
|
+
*/
|
|
120
|
+
get persistentStorage() {
|
|
121
|
+
return this.mediator.getComponent('persistentStorageManager');
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Forces a save of the persistent storage.
|
|
125
|
+
*/
|
|
126
|
+
async forceSave() {
|
|
127
|
+
await this.persistentStorage.save();
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Changes the library's passphrase.
|
|
131
|
+
* @param oldPassphrase - The current passphrase.
|
|
132
|
+
* @param newPassphrase - The new passphrase to set.
|
|
133
|
+
* @returns A promise that resolves when the passphrase change is complete.
|
|
134
|
+
* @throws {AuthenticationError} If the provided old passphrase is incorrect.
|
|
135
|
+
*/
|
|
136
|
+
async changePassphrase(oldPassphrase, newPassphrase) {
|
|
137
|
+
return this.persistentStorage.changePassphrase(oldPassphrase, newPassphrase);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Sets a server url, this will allow syncing with the server.
|
|
141
|
+
* @param serverUrl - The server url.
|
|
142
|
+
*/
|
|
143
|
+
async setSyncServerUrl(serverUrl) {
|
|
144
|
+
if (this.sync) {
|
|
145
|
+
this.sync.closeServerConnection();
|
|
146
|
+
this.mediator.unRegisterComponent('syncManager');
|
|
147
|
+
}
|
|
148
|
+
const newSyncState = {
|
|
149
|
+
serverUrl,
|
|
150
|
+
devices: [],
|
|
151
|
+
commandSendQueue: [],
|
|
152
|
+
};
|
|
153
|
+
this.setSyncState(newSyncState);
|
|
154
|
+
await this.forceSave();
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Sets the sync state, this will initiate the sync manager instance.
|
|
158
|
+
* @param syncState - The state of the sync.
|
|
159
|
+
*/
|
|
160
|
+
setSyncState(syncState) {
|
|
161
|
+
this.mediator.registerComponent('syncManager', new SyncManager(this.mediator, this.deviceType, this.publicKey, this.privateKey, syncState, this.deviceId));
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Dispatches a library event.
|
|
165
|
+
* @param eventType - The type of the event to dispatch, uses the TwoFaLibEvent enum.
|
|
166
|
+
* @param data - Optional data to include with the event.
|
|
167
|
+
*/
|
|
168
|
+
dispatchLibEvent(eventType, data) {
|
|
169
|
+
this.dispatchTypedEvent(eventType, new CustomEvent(eventType, { detail: data }));
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Log a message
|
|
173
|
+
* @param severity - The severity of the message, either 'info' or 'warning'.
|
|
174
|
+
* @param message - The message to log.
|
|
175
|
+
*/
|
|
176
|
+
log(severity, message) {
|
|
177
|
+
this.dispatchLibEvent(TwoFaLibEvent.Log, { severity, message });
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
export default TwoFaLib;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare enum TwoFaLibEvent {
|
|
2
|
+
Changed = "changed",
|
|
3
|
+
LoadedFromLockedRepresentation = "loadedFromLockedRepresentation",
|
|
4
|
+
ConnectToExistingVaultFinished = "connectToExistingVaultFinished",
|
|
5
|
+
ConnectionToSyncServerStatusChanged = "connectionToSyncServerStatusChanged",
|
|
6
|
+
Log = "log",
|
|
7
|
+
Ready = "ready"
|
|
8
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export var TwoFaLibEvent;
|
|
2
|
+
(function (TwoFaLibEvent) {
|
|
3
|
+
TwoFaLibEvent["Changed"] = "changed";
|
|
4
|
+
TwoFaLibEvent["LoadedFromLockedRepresentation"] = "loadedFromLockedRepresentation";
|
|
5
|
+
TwoFaLibEvent["ConnectToExistingVaultFinished"] = "connectToExistingVaultFinished";
|
|
6
|
+
TwoFaLibEvent["ConnectionToSyncServerStatusChanged"] = "connectionToSyncServerStatusChanged";
|
|
7
|
+
TwoFaLibEvent["Log"] = "log";
|
|
8
|
+
TwoFaLibEvent["Ready"] = "ready";
|
|
9
|
+
})(TwoFaLibEvent || (TwoFaLibEvent = {}));
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mediator class for managing and accessing various components of the TwoFaLib.
|
|
3
|
+
*/
|
|
4
|
+
declare class TwoFaLibMediator {
|
|
5
|
+
private components;
|
|
6
|
+
/**
|
|
7
|
+
* Unregister a component with the mediator. Is used in testing
|
|
8
|
+
* @param key - The key representing the component type.
|
|
9
|
+
*/
|
|
10
|
+
unRegisterComponent<T extends keyof typeof this.components>(key: T): void;
|
|
11
|
+
/**
|
|
12
|
+
* Registers a single component with the mediator.
|
|
13
|
+
* @param key - The key representing the component type.
|
|
14
|
+
* @param component - The component instance to register.
|
|
15
|
+
* @throws {InitializationError} If the component is already registered.
|
|
16
|
+
*/
|
|
17
|
+
registerComponent<T extends keyof typeof this.components>(key: T, component: NonNullable<(typeof this.components)[T]>): void;
|
|
18
|
+
/**
|
|
19
|
+
* Registers multiple components with the mediator.
|
|
20
|
+
* @param componentsArray - An array of key-component pairs to register.
|
|
21
|
+
*/
|
|
22
|
+
registerComponents<T extends keyof typeof this.components>(componentsArray: [T, NonNullable<(typeof this.components)[T]>][]): void;
|
|
23
|
+
/**
|
|
24
|
+
* Retrieves a component by its key.
|
|
25
|
+
* @param key - The key representing the component type.
|
|
26
|
+
* @returns The component instance.
|
|
27
|
+
* @throws {InitializationError} If the component is not initialized.
|
|
28
|
+
*/
|
|
29
|
+
getComponent<T extends keyof typeof this.components>(key: T): NonNullable<(typeof this.components)[T]>;
|
|
30
|
+
/**
|
|
31
|
+
* Checks if a component is initialized.
|
|
32
|
+
* @param key - The key representing the component type.
|
|
33
|
+
* @returns True if the component is initialized, false otherwise.
|
|
34
|
+
*/
|
|
35
|
+
componentIsInitialised<T extends keyof typeof this.components>(key: T): boolean;
|
|
36
|
+
}
|
|
37
|
+
export default TwoFaLibMediator;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { InitializationError } from './TwoFALibError.mjs';
|
|
2
|
+
/**
|
|
3
|
+
* Mediator class for managing and accessing various components of the TwoFaLib.
|
|
4
|
+
*/
|
|
5
|
+
class TwoFaLibMediator {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.components = {};
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Unregister a component with the mediator. Is used in testing
|
|
11
|
+
* @param key - The key representing the component type.
|
|
12
|
+
*/
|
|
13
|
+
unRegisterComponent(key) {
|
|
14
|
+
this.components[key] = undefined;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Registers a single component with the mediator.
|
|
18
|
+
* @param key - The key representing the component type.
|
|
19
|
+
* @param component - The component instance to register.
|
|
20
|
+
* @throws {InitializationError} If the component is already registered.
|
|
21
|
+
*/
|
|
22
|
+
registerComponent(key, component) {
|
|
23
|
+
if (this.components[key]) {
|
|
24
|
+
throw new InitializationError(`Component ${key} already registered`);
|
|
25
|
+
}
|
|
26
|
+
this.components[key] = component;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Registers multiple components with the mediator.
|
|
30
|
+
* @param componentsArray - An array of key-component pairs to register.
|
|
31
|
+
*/
|
|
32
|
+
registerComponents(componentsArray) {
|
|
33
|
+
for (const [key, component] of componentsArray) {
|
|
34
|
+
this.registerComponent(key, component);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Retrieves a component by its key.
|
|
39
|
+
* @param key - The key representing the component type.
|
|
40
|
+
* @returns The component instance.
|
|
41
|
+
* @throws {InitializationError} If the component is not initialized.
|
|
42
|
+
*/
|
|
43
|
+
getComponent(key) {
|
|
44
|
+
if (!this.components[key]) {
|
|
45
|
+
throw new InitializationError(`${key} is not initialized`);
|
|
46
|
+
}
|
|
47
|
+
return this.components[key];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Checks if a component is initialized.
|
|
51
|
+
* @param key - The key representing the component type.
|
|
52
|
+
* @returns True if the component is initialized, false otherwise.
|
|
53
|
+
*/
|
|
54
|
+
componentIsInitialised(key) {
|
|
55
|
+
return Boolean(this.components[key]);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export default TwoFaLibMediator;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AddEntryData } from '../Command/commands/AddEntryCommand.mjs';
|
|
2
|
+
import type { DeleteEntryData } from '../Command/commands/DeleteEntryCommand.mjs';
|
|
3
|
+
import type { UpdateEntryData } from '../Command/commands/UpdateEntryCommand.mjs';
|
|
4
|
+
import type { AddSyncDeviceData } from '../Command/commands/AddSyncDeviceCommand.mjs';
|
|
5
|
+
export type SyncCommand = ({
|
|
6
|
+
type: 'AddEntry';
|
|
7
|
+
data: AddEntryData;
|
|
8
|
+
} | {
|
|
9
|
+
type: 'DeleteEntry';
|
|
10
|
+
data: DeleteEntryData;
|
|
11
|
+
} | {
|
|
12
|
+
type: 'UpdateEntry';
|
|
13
|
+
data: UpdateEntryData;
|
|
14
|
+
} | {
|
|
15
|
+
type: 'AddSyncDevice';
|
|
16
|
+
data: AddSyncDeviceData;
|
|
17
|
+
}) & {
|
|
18
|
+
id: string;
|
|
19
|
+
};
|
|
20
|
+
export type CommandData = AddEntryData | DeleteEntryData | UpdateEntryData | AddSyncDeviceData;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { Tagged } from 'type-fest';
|
|
2
|
+
export type Encrypted<T extends string> = Tagged<T, 'Encrypted'>;
|
|
3
|
+
/** Represents a passphrase */
|
|
4
|
+
export type Passphrase = Tagged<string, 'Passphrase'>;
|
|
5
|
+
/** Represents a passphraseHash */
|
|
6
|
+
export type PassphraseHash = Tagged<string, 'PassphraseHash'>;
|
|
7
|
+
/** Represents a salt (base64 encoded) */
|
|
8
|
+
export type Salt = Tagged<string, 'Salt'>;
|
|
9
|
+
/** Represents a private key */
|
|
10
|
+
export type PrivateKey = Tagged<string, 'PrivateKey'>;
|
|
11
|
+
/** Represents a public key */
|
|
12
|
+
export type PublicKey = Tagged<string, 'PublicKey'>;
|
|
13
|
+
/** Represents an symmetric key */
|
|
14
|
+
export type SymmetricKey = Tagged<string, 'SymmetricKey'>;
|
|
15
|
+
/** Represents a sync (symmetric) key (base64 encoded) */
|
|
16
|
+
export type SyncKey = Tagged<SymmetricKey, 'SyncKey'>;
|
|
17
|
+
/** Represents an encrypted private key (base64 encoded) */
|
|
18
|
+
export type EncryptedPrivateKey = Encrypted<PrivateKey>;
|
|
19
|
+
/** Represents an encrypted symmetric key (base64 encoded) */
|
|
20
|
+
export type EncryptedSymmetricKey = Encrypted<SymmetricKey>;
|
|
21
|
+
/** Represents an encrypted public key (base64 encoded) */
|
|
22
|
+
export type EncryptedPublicKey = Encrypted<PublicKey>;
|
|
23
|
+
/**
|
|
24
|
+
* Interface for cryptographic operations.
|
|
25
|
+
* The implementation in CryptoProviders/node is the reference implementation
|
|
26
|
+
*/
|
|
27
|
+
interface CryptoLib {
|
|
28
|
+
/**
|
|
29
|
+
* Get a number of cryptographically securely generated random bytes
|
|
30
|
+
* @param count - The amount of bytes to generate
|
|
31
|
+
* @returns A promise that resolves to the generated random bytes
|
|
32
|
+
*/
|
|
33
|
+
getRandomBytes: (count: number) => Promise<Uint8Array>;
|
|
34
|
+
/**
|
|
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 passphrase.
|
|
37
|
+
* It then generates a symmetricKey. It will then encrypt this symmetricKey using the generated public key.
|
|
38
|
+
* @param passphrase - The passphrase to encrypt the private key with
|
|
39
|
+
* @returns A promise that resolves to an object containing the encrypted private key, encrypted symmetric key and public key
|
|
40
|
+
*/
|
|
41
|
+
createKeys: (passphrase: Passphrase) => Promise<{
|
|
42
|
+
privateKey: PrivateKey;
|
|
43
|
+
symmetricKey: SymmetricKey;
|
|
44
|
+
encryptedPrivateKey: EncryptedPrivateKey;
|
|
45
|
+
encryptedSymmetricKey: EncryptedSymmetricKey;
|
|
46
|
+
publicKey: PublicKey;
|
|
47
|
+
salt: Salt;
|
|
48
|
+
}>;
|
|
49
|
+
/**
|
|
50
|
+
* Decrypts the keys required for further operations
|
|
51
|
+
* @param encryptedPrivateKey - The encrypted private key
|
|
52
|
+
* @param encryptedSymmetricKey - The encrypted symmetric key
|
|
53
|
+
* @param passphrase - The passphrase to decrypt the private key with
|
|
54
|
+
* @returns A promise that resolves to an object containing the decrypted private, symmetric and public key
|
|
55
|
+
*/
|
|
56
|
+
decryptKeys: (encryptedPrivateKey: EncryptedPrivateKey, encryptedSymmetricKey: EncryptedSymmetricKey, salt: Salt, passphrase: Passphrase) => Promise<{
|
|
57
|
+
privateKey: PrivateKey;
|
|
58
|
+
symmetricKey: SymmetricKey;
|
|
59
|
+
publicKey: PublicKey;
|
|
60
|
+
}>;
|
|
61
|
+
/**
|
|
62
|
+
* Encrypts the keys required for further operation
|
|
63
|
+
* @param privateKey - The private key to encrypt
|
|
64
|
+
* @param symmetricKey - The symmetric key to encrypt
|
|
65
|
+
* @param passphrase - The passphrase to encrypt the private key with
|
|
66
|
+
* @returns A promise that resolves to an object containing the encrypted private and symmetricKey key
|
|
67
|
+
*/
|
|
68
|
+
encryptKeys: (privateKey: PrivateKey, symmetricKey: SymmetricKey, salt: Salt, passphrase: Passphrase) => Promise<{
|
|
69
|
+
encryptedPrivateKey: EncryptedPrivateKey;
|
|
70
|
+
encryptedSymmetricKey: EncryptedSymmetricKey;
|
|
71
|
+
}>;
|
|
72
|
+
/**
|
|
73
|
+
* Encrypts a plain text message using a public key
|
|
74
|
+
* @param publicKey - The public key to use for encryption
|
|
75
|
+
* @param plainText - The text to encrypt
|
|
76
|
+
* @returns A promise that resolves to the encrypted text (base64 encoded)
|
|
77
|
+
*/
|
|
78
|
+
encrypt: <T extends string>(publicKey: PublicKey, plainText: T) => Promise<Encrypted<T>>;
|
|
79
|
+
/**
|
|
80
|
+
* Decrypts an encrypted message using a private key
|
|
81
|
+
* @param privateKey - The (unencrypted!) private key to use for decryption
|
|
82
|
+
* @param encryptedText - The text to decrypt
|
|
83
|
+
* @returns A promise that resolves to the decrypted text
|
|
84
|
+
*/
|
|
85
|
+
decrypt: <T extends string>(privateKey: PrivateKey, encryptedText: Encrypted<T>) => Promise<T>;
|
|
86
|
+
/**
|
|
87
|
+
* Decrypts an encrypted message using a symmetric key
|
|
88
|
+
* @param symmetricKey - The symmetric key to use for decryption
|
|
89
|
+
* @param encryptedText - The text to decrypt
|
|
90
|
+
* @returns A promise that resolves to the decrypted text
|
|
91
|
+
*/
|
|
92
|
+
decryptSymmetric: <T extends string>(symmetricKey: SymmetricKey, encryptedText: Encrypted<T>) => Promise<T>;
|
|
93
|
+
/**
|
|
94
|
+
* Encrypts a plain text message using a symmetric key
|
|
95
|
+
* @param symmetricKey - The symmetric key to use for encryption
|
|
96
|
+
* @param plainText - The text to encrypt
|
|
97
|
+
* @returns A promise that resolves to the encrypted text (base64 encoded)
|
|
98
|
+
*/
|
|
99
|
+
encryptSymmetric: <T extends string>(symmetricKey: SymmetricKey, plainText: T) => Promise<Encrypted<T>>;
|
|
100
|
+
/**
|
|
101
|
+
* Creates a random symmetric key
|
|
102
|
+
* @returns A promise that resolves to the newly created symmetric key
|
|
103
|
+
*/
|
|
104
|
+
createSymmetricKey: () => Promise<SymmetricKey>;
|
|
105
|
+
/**
|
|
106
|
+
* Creates a sync key from a shared key (that was created from a JPAKE exchange)
|
|
107
|
+
* @param sharedKey - The shared key to derive from
|
|
108
|
+
* @param salt - A salt to derive the key with
|
|
109
|
+
* @returns A promise that resolves to the derived key
|
|
110
|
+
*/
|
|
111
|
+
createSyncKey: (sharedKey: Uint8Array, salt: Salt) => Promise<SyncKey>;
|
|
112
|
+
}
|
|
113
|
+
export default CryptoLib;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { LiteralUnion } from 'type-fest';
|
|
2
|
+
import type { Tagged } from 'type-fest';
|
|
3
|
+
export type EntryId = Tagged<string, 'TotpId'>;
|
|
4
|
+
export type EntryType = LiteralUnion<'TOTP', string>;
|
|
5
|
+
export interface EntryMeta {
|
|
6
|
+
id: EntryId;
|
|
7
|
+
name: string;
|
|
8
|
+
issuer: string;
|
|
9
|
+
type: EntryType;
|
|
10
|
+
addedAt: number;
|
|
11
|
+
updatedAt: number | null;
|
|
12
|
+
}
|
|
13
|
+
export interface TotpPayload {
|
|
14
|
+
secret: string;
|
|
15
|
+
period: LiteralUnion<30 | 60, number>;
|
|
16
|
+
algorithm: LiteralUnion<'SHA-1' | 'SHA-256' | 'SHA-512', string>;
|
|
17
|
+
digits: LiteralUnion<6 | 8, number>;
|
|
18
|
+
}
|
|
19
|
+
interface TotpEntry extends EntryMeta {
|
|
20
|
+
type: 'TOTP';
|
|
21
|
+
payload: TotpPayload;
|
|
22
|
+
}
|
|
23
|
+
type Entry = TotpEntry;
|
|
24
|
+
export type NewEntry = Omit<Entry, 'id' | 'addedAt' | 'updatedAt'>;
|
|
25
|
+
export default Entry;
|
|
26
|
+
export interface Token {
|
|
27
|
+
validFrom: number;
|
|
28
|
+
validTill: number;
|
|
29
|
+
otp: string;
|
|
30
|
+
}
|
|
31
|
+
export type EntryMetaWithToken = EntryMeta & {
|
|
32
|
+
token: Token;
|
|
33
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { EmptyObject } from 'type-fest';
|
|
2
|
+
import type { TwoFaLibEvent } from '../TwoFaLibEvent.mjs';
|
|
3
|
+
import type { LockedRepresentationString } from './Vault.mjs';
|
|
4
|
+
export interface ChangedEvent {
|
|
5
|
+
newLockedRepresentationString: LockedRepresentationString;
|
|
6
|
+
}
|
|
7
|
+
export interface TwoFaLibEventMap {
|
|
8
|
+
[TwoFaLibEvent.Changed]: ChangedEvent;
|
|
9
|
+
[TwoFaLibEvent.LoadedFromLockedRepresentation]: EmptyObject;
|
|
10
|
+
[TwoFaLibEvent.ConnectToExistingVaultFinished]: EmptyObject;
|
|
11
|
+
[TwoFaLibEvent.ConnectionToSyncServerStatusChanged]: {
|
|
12
|
+
connected: boolean;
|
|
13
|
+
};
|
|
14
|
+
[TwoFaLibEvent.Log]: {
|
|
15
|
+
severity: 'info' | 'warning';
|
|
16
|
+
message: string;
|
|
17
|
+
};
|
|
18
|
+
[TwoFaLibEvent.Ready]: EmptyObject;
|
|
19
|
+
}
|
|
20
|
+
export type TwoFaLibEventMapEvents = {
|
|
21
|
+
[K in keyof TwoFaLibEventMap]: CustomEvent<TwoFaLibEventMap[K]>;
|
|
22
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Tagged } from 'type-fest';
|
|
2
|
+
import type { JPakeThreePass, Round1Result } from 'jpake-ts';
|
|
3
|
+
import { PublicKey, SyncKey } from './CryptoLib.mjs';
|
|
4
|
+
export type DeviceId = Tagged<string, 'DeviceId'>;
|
|
5
|
+
export type DeviceType = Tagged<string, 'DeviceType'>;
|
|
6
|
+
export interface SyncDevice {
|
|
7
|
+
deviceId: DeviceId;
|
|
8
|
+
deviceType: DeviceType;
|
|
9
|
+
publicKey: PublicKey;
|
|
10
|
+
}
|
|
11
|
+
export interface BaseAddDeviceFlow {
|
|
12
|
+
jpak: JPakeThreePass;
|
|
13
|
+
addDevicePassword: Uint8Array;
|
|
14
|
+
timestamp: number;
|
|
15
|
+
}
|
|
16
|
+
export interface AddDeviceFlowInitiator_Initiated extends BaseAddDeviceFlow {
|
|
17
|
+
state: 'initiator:initiated';
|
|
18
|
+
resolveContinuePromise: (value: unknown) => void;
|
|
19
|
+
initiatorDeviceId: DeviceId;
|
|
20
|
+
timeout: NodeJS.Timeout;
|
|
21
|
+
}
|
|
22
|
+
export interface AddDeviceFlowInitiator_SyncKeyCreated extends Omit<AddDeviceFlowInitiator_Initiated, 'state' | 'resolveContinuePromise'> {
|
|
23
|
+
state: 'initiator:syncKeyCreated';
|
|
24
|
+
responderDeviceId: DeviceId;
|
|
25
|
+
responderDeviceType: DeviceType;
|
|
26
|
+
syncKey: SyncKey;
|
|
27
|
+
}
|
|
28
|
+
export interface AddDeviceFlowResponder_Initiated extends BaseAddDeviceFlow {
|
|
29
|
+
state: 'responder:initated';
|
|
30
|
+
initiatorDeviceId: DeviceId;
|
|
31
|
+
responderDeviceId: DeviceId;
|
|
32
|
+
initiatorDeviceType: DeviceType;
|
|
33
|
+
}
|
|
34
|
+
export interface AddDeviceFlowResponder_SyncKeyCreated extends Omit<AddDeviceFlowResponder_Initiated, 'state'> {
|
|
35
|
+
state: 'responder:syncKeyCreated';
|
|
36
|
+
syncKey: SyncKey;
|
|
37
|
+
}
|
|
38
|
+
export type ActiveAddDeviceFlow = AddDeviceFlowInitiator_Initiated | AddDeviceFlowInitiator_SyncKeyCreated | AddDeviceFlowResponder_Initiated | AddDeviceFlowResponder_SyncKeyCreated;
|
|
39
|
+
export interface InitiateAddDeviceFlowResult {
|
|
40
|
+
addDevicePassword: string;
|
|
41
|
+
initiatorDeviceId: DeviceId;
|
|
42
|
+
initiatorDeviceType: DeviceType;
|
|
43
|
+
timestamp: number;
|
|
44
|
+
pass1Result: Record<keyof Round1Result, string>;
|
|
45
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|