favalib 0.0.11 → 0.0.12

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.
Files changed (38) hide show
  1. package/build/TwoFaLib.d.mts +3 -3
  2. package/build/TwoFaLib.mjs +16 -12
  3. package/build/interfaces/OpenPgpLib.d.mts +20 -0
  4. package/build/interfaces/OpenPgpLib.mjs +1 -0
  5. package/build/interfaces/PlatformProviders.d.mts +26 -0
  6. package/build/interfaces/PlatformProviders.mjs +1 -0
  7. package/build/interfaces/QrCodeLib.d.mts +19 -0
  8. package/build/interfaces/QrCodeLib.mjs +1 -0
  9. package/build/main.d.mts +2 -1
  10. package/build/platformProviders/browser/index.d.mts +6 -0
  11. package/build/platformProviders/browser/index.mjs +13 -0
  12. package/build/platformProviders/browser/openPgpLib.d.mts +20 -0
  13. package/build/platformProviders/browser/openPgpLib.mjs +44 -0
  14. package/build/platformProviders/browser/qrCodeLib.d.mts +25 -0
  15. package/build/platformProviders/browser/qrCodeLib.mjs +69 -0
  16. package/build/{CryptoProviders/node/index.mjs → platformProviders/node/cryptoLib.mjs} +1 -1
  17. package/build/platformProviders/node/index.d.mts +6 -0
  18. package/build/platformProviders/node/index.mjs +13 -0
  19. package/build/platformProviders/node/openPgpLib.d.mts +20 -0
  20. package/build/platformProviders/node/openPgpLib.mjs +44 -0
  21. package/build/platformProviders/node/qrCodeLib.d.mts +28 -0
  22. package/build/platformProviders/node/qrCodeLib.mjs +54 -0
  23. package/build/subclasses/ExportImportManager.mjs +3 -3
  24. package/build/subclasses/LibraryLoader.d.mts +26 -12
  25. package/build/subclasses/LibraryLoader.mjs +26 -34
  26. package/build/subclasses/SyncManager.mjs +7 -6
  27. package/build/utils/creationUtils.d.mts +3 -3
  28. package/build/utils/creationUtils.mjs +7 -5
  29. package/build/utils/exportImportUtils.d.mts +5 -3
  30. package/build/utils/exportImportUtils.mjs +2 -12
  31. package/build/utils/qrUtils.d.mts +0 -16
  32. package/build/utils/qrUtils.mjs +2 -68
  33. package/build/utils/syncUtils.d.mts +3 -2
  34. package/build/utils/syncUtils.mjs +3 -19
  35. package/package.json +8 -8
  36. /package/build/{CryptoProviders/browser/index.d.mts → platformProviders/browser/cryptoLib.d.mts} +0 -0
  37. /package/build/{CryptoProviders/browser/index.mjs → platformProviders/browser/cryptoLib.mjs} +0 -0
  38. /package/build/{CryptoProviders/node/index.d.mts → platformProviders/node/cryptoLib.d.mts} +0 -0
@@ -1,5 +1,5 @@
1
1
  import { TypedEventTarget } from 'typescript-event-target';
2
- import type CryptoLib from './interfaces/CryptoLib.mjs';
2
+ 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';
@@ -34,7 +34,7 @@ declare class TwoFaLib extends TypedEventTarget<TwoFaLibEventMapEvents> {
34
34
  /**
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
- * @param cryptoLib - An instance of CryptoLib that is compatible with the environment.
37
+ * @param platformProviders - The platform-specific providers containing CryptoLib and other providers.
38
38
  * @param passphraseExtraDict - Additional words to be used for passphrase strength evaluation.
39
39
  * @param privateKey - The private key used for cryptographic operations.
40
40
  * @param symmetricKey - The symmetric key used for cryptographic operations.
@@ -50,7 +50,7 @@ declare class TwoFaLib extends TypedEventTarget<TwoFaLibEventMapEvents> {
50
50
  * @throws {InitializationError} If some parameter has an invalid value
51
51
  * @throws {AuthenticationError} If the provided passphrase is incorrect.
52
52
  */
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);
53
+ constructor(deviceType: DeviceType, platformProviders: PlatformProviders, passphraseExtraDict: PassphraseExtraDict, 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
  */
@@ -30,7 +30,7 @@ class TwoFaLib extends TypedEventTarget {
30
30
  /**
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
- * @param cryptoLib - An instance of CryptoLib that is compatible with the environment.
33
+ * @param platformProviders - The platform-specific providers containing CryptoLib and other providers.
34
34
  * @param passphraseExtraDict - Additional words to be used for passphrase strength evaluation.
35
35
  * @param privateKey - The private key used for cryptographic operations.
36
36
  * @param symmetricKey - The symmetric key used for cryptographic operations.
@@ -46,7 +46,7 @@ class TwoFaLib extends TypedEventTarget {
46
46
  * @throws {InitializationError} If some parameter has an invalid value
47
47
  * @throws {AuthenticationError} If the provided passphrase is incorrect.
48
48
  */
49
- constructor(deviceType, cryptoLib, passphraseExtraDict, privateKey, symmetricKey, encryptedPrivateKey, encryptedSymmetricKey, salt, publicKey, favaMeta, vault, saveFunction, syncState) {
49
+ constructor(deviceType, platformProviders, passphraseExtraDict, 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');
@@ -70,7 +70,7 @@ class TwoFaLib extends TypedEventTarget {
70
70
  this.privateKey = privateKey;
71
71
  this.mediator = new TwoFaLibMediator();
72
72
  this.mediator.registerComponents([
73
- ['libraryLoader', new LibraryLoader(cryptoLib)],
73
+ ['libraryLoader', new LibraryLoader(platformProviders)],
74
74
  [
75
75
  'persistentStorageManager',
76
76
  new PersistentStorageManager(this.mediator, passphraseExtraDict, favaMeta, privateKey, symmetricKey, encryptedPrivateKey, encryptedSymmetricKey, salt, saveFunction),
@@ -153,9 +153,10 @@ class TwoFaLib extends TypedEventTarget {
153
153
  * @param force - Force setting the sync server url, even if no connection can be made
154
154
  */
155
155
  async setSyncServerUrl(serverUrl, force = false) {
156
- if (this.sync) {
156
+ const oldSyncManager = this.sync;
157
+ if (oldSyncManager) {
157
158
  // close connection so no data is send to the old syncServer
158
- this.sync.closeServerConnection();
159
+ oldSyncManager.closeServerConnection();
159
160
  }
160
161
  const newSyncState = {
161
162
  serverUrl,
@@ -163,6 +164,9 @@ class TwoFaLib extends TypedEventTarget {
163
164
  commandSendQueue: [],
164
165
  };
165
166
  const newSyncManager = new SyncManager(this.mediator, this.publicKey, this.privateKey, this.favaMeta, newSyncState, this.deviceType);
167
+ // Temporarily register the new sync manager so its events can be heard
168
+ this.mediator.unRegisterComponent('syncManager');
169
+ this.mediator.registerComponent('syncManager', newSyncManager);
166
170
  const success = await new Promise((resolve) => {
167
171
  this.addEventListener(TwoFaLibEvent.ConnectionToSyncServerStatusChanged, (event) => {
168
172
  if (event.detail.newStatus === ConnectionStatus.CONNECTED) {
@@ -178,18 +182,18 @@ class TwoFaLib extends TypedEventTarget {
178
182
  this.log('warning', `Failed to connect to server at ${serverUrl}, force setting`);
179
183
  }
180
184
  else {
181
- if (this.sync) {
185
+ // Close the new sync manager and restore the old one
186
+ newSyncManager.closeServerConnection();
187
+ this.mediator.unRegisterComponent('syncManager');
188
+ if (oldSyncManager) {
182
189
  // re-establish old connection
183
- this.sync.initServerConnection();
190
+ this.mediator.registerComponent('syncManager', oldSyncManager);
191
+ oldSyncManager.initServerConnection();
184
192
  }
185
- newSyncManager.closeServerConnection();
186
193
  throw new SyncError(`Failed to connect to server at ${serverUrl}, not setting`);
187
194
  }
188
195
  }
189
- // connection succeeded (or force=true)
190
- // switch to the new syncManager
191
- this.mediator.unRegisterComponent('syncManager');
192
- this.mediator.registerComponent('syncManager', newSyncManager);
196
+ // connection succeeded (or force=true) - new sync manager is already registered
193
197
  // save
194
198
  await this.persistentStorageManager.save();
195
199
  }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Interface for OpenPGP operations
3
+ */
4
+ export interface OpenPgpLib {
5
+ /**
6
+ * Encrypts the given data using OpenPGP.
7
+ * @param data - The data to encrypt.
8
+ * @param password - The password to use for encryption.
9
+ * @returns A promise that resolves to the encrypted data.
10
+ */
11
+ encrypt(data: string, password: string): Promise<string>;
12
+ /**
13
+ * Decrypts the given data using OpenPGP.
14
+ * @param data - The data to decrypt.
15
+ * @param password - The password to use for decryption.
16
+ * @returns A promise that resolves to the decrypted data.
17
+ */
18
+ decrypt(data: string, password: string): Promise<string>;
19
+ }
20
+ export default OpenPgpLib;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,26 @@
1
+ import type CryptoLib from './CryptoLib.mjs';
2
+ import type { QrCodeLib } from './QrCodeLib.mjs';
3
+ import type { OpenPgpLib } from './OpenPgpLib.mjs';
4
+ /**
5
+ * Interface for platform-specific providers
6
+ * Includes platform-specific implementations for various libraries
7
+ */
8
+ export interface PlatformProviders {
9
+ /**
10
+ * Cryptographic operations provider
11
+ */
12
+ CryptoLib: new () => CryptoLib;
13
+ /**
14
+ * WebSocket library
15
+ */
16
+ WebSocketLib: () => typeof WebSocket;
17
+ /**
18
+ * QR code generation library with platform-specific extensions
19
+ */
20
+ QrCodeLib: new () => QrCodeLib;
21
+ /**
22
+ * OpenPGP encryption library
23
+ */
24
+ OpenPgpLib: new () => OpenPgpLib;
25
+ }
26
+ export default PlatformProviders;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,19 @@
1
+ import type { ImageData } from 'canvas';
2
+ /**
3
+ * Interface for QR code operations
4
+ */
5
+ export interface QrCodeLib {
6
+ /**
7
+ * Generates a QR code as a data URL.
8
+ * @param text - The text to encode.
9
+ * @returns A promise that resolves to a data URL string.
10
+ */
11
+ toDataURL(text: string): Promise<string>;
12
+ /**
13
+ * Gets ImageData from various input types for QR code processing.
14
+ * @param imageInput - The image input (string URL, File, or Uint8Array).
15
+ * @returns A promise that resolves to ImageData.
16
+ */
17
+ getImageDataFromInput(imageInput: string | File | Uint8Array): Promise<ImageData>;
18
+ }
19
+ export default QrCodeLib;
@@ -0,0 +1 @@
1
+ export {};
package/build/main.d.mts CHANGED
@@ -6,8 +6,9 @@ import type { Encrypted, EncryptedPrivateKey, EncryptedSymmetricKey, EncryptedPu
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';
9
+ import type { PlatformProviders } from './interfaces/PlatformProviders.mjs';
9
10
  import { TwoFALibError, InitializationError, AuthenticationError, EntryNotFoundError, TokenGenerationError } from './TwoFALibError.mjs';
10
11
  import { TwoFaLibEvent } from './TwoFaLibEvent.mjs';
11
12
  import { getTwoFaLibVaultCreationUtils } from './utils/creationUtils.mjs';
12
13
  export { TwoFaLib, TwoFALibError, getTwoFaLibVaultCreationUtils, InitializationError, AuthenticationError, EntryNotFoundError, TokenGenerationError, TwoFaLibEvent, };
13
- export type { Entry, EntryId, NewEntry, EntryMeta, EntryMetaWithToken, EntryType, TotpPayload, Token, EncryptedVaultStateString, LockedRepresentationString, CryptoLib, Encrypted, EncryptedPrivateKey, EncryptedPublicKey, EncryptedSymmetricKey, PrivateKey, SymmetricKey, PublicKey, Passphrase, Salt, DeviceId, DeviceType, DeviceFriendlyName, DeviceInfo, PublicSyncDevice, SaveFunction, };
14
+ export type { Entry, EntryId, NewEntry, EntryMeta, EntryMetaWithToken, EntryType, TotpPayload, Token, EncryptedVaultStateString, LockedRepresentationString, CryptoLib, Encrypted, EncryptedPrivateKey, EncryptedPublicKey, EncryptedSymmetricKey, PrivateKey, SymmetricKey, PublicKey, Passphrase, Salt, DeviceId, DeviceType, DeviceFriendlyName, DeviceInfo, PublicSyncDevice, SaveFunction, PlatformProviders, };
@@ -0,0 +1,6 @@
1
+ import type { PlatformProviders } from '../../interfaces/PlatformProviders.mjs';
2
+ /**
3
+ * Browser-specific platform providers
4
+ */
5
+ export declare const browserProviders: PlatformProviders;
6
+ export default browserProviders;
@@ -0,0 +1,13 @@
1
+ import BrowserCryptoLib from './cryptoLib.mjs';
2
+ import { BrowserQrCodeLib } from './qrCodeLib.mjs';
3
+ import { BrowserOpenPgpLib } from './openPgpLib.mjs';
4
+ /**
5
+ * Browser-specific platform providers
6
+ */
7
+ export const browserProviders = {
8
+ CryptoLib: BrowserCryptoLib,
9
+ WebSocketLib: () => WebSocket,
10
+ QrCodeLib: BrowserQrCodeLib,
11
+ OpenPgpLib: BrowserOpenPgpLib,
12
+ };
13
+ export default browserProviders;
@@ -0,0 +1,20 @@
1
+ import type { OpenPgpLib } from '../../interfaces/OpenPgpLib.mjs';
2
+ /**
3
+ * Browser implementation of OpenPGP library wrapper
4
+ */
5
+ export declare class BrowserOpenPgpLib implements OpenPgpLib {
6
+ private openPgpModule;
7
+ /**
8
+ * Gets the OpenPGP module, loading it if necessary
9
+ * @returns Promise that resolves to the OpenPGP module
10
+ */
11
+ private getOpenPgpModule;
12
+ /**
13
+ * @inheritdoc
14
+ */
15
+ encrypt(data: string, password: string): Promise<string>;
16
+ /**
17
+ * @inheritdoc
18
+ */
19
+ decrypt(data: string, password: string): Promise<string>;
20
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Browser implementation of OpenPGP library wrapper
3
+ */
4
+ export class BrowserOpenPgpLib {
5
+ constructor() {
6
+ this.openPgpModule = null;
7
+ }
8
+ /**
9
+ * Gets the OpenPGP module, loading it if necessary
10
+ * @returns Promise that resolves to the OpenPGP module
11
+ */
12
+ async getOpenPgpModule() {
13
+ if (!this.openPgpModule) {
14
+ this.openPgpModule = await import('openpgp');
15
+ // enable Authenticated Encryption with Associated Data
16
+ this.openPgpModule.config.aeadProtect = true;
17
+ }
18
+ return this.openPgpModule;
19
+ }
20
+ /**
21
+ * @inheritdoc
22
+ */
23
+ async encrypt(data, password) {
24
+ const openPgp = await this.getOpenPgpModule();
25
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
26
+ const encrypted = await openPgp.encrypt({
27
+ message: await openPgp.createMessage({ text: data }),
28
+ passwords: [password],
29
+ format: 'armored',
30
+ });
31
+ return encrypted;
32
+ }
33
+ /**
34
+ * @inheritdoc
35
+ */
36
+ async decrypt(data, password) {
37
+ const openPgp = await this.getOpenPgpModule();
38
+ const decrypted = await openPgp.decrypt({
39
+ message: await openPgp.readMessage({ armoredMessage: data }),
40
+ passwords: [password],
41
+ });
42
+ return decrypted.data;
43
+ }
44
+ }
@@ -0,0 +1,25 @@
1
+ import type { ImageData } from 'canvas';
2
+ import type { QrCodeLib } from '../../interfaces/QrCodeLib.mjs';
3
+ /**
4
+ * Gets the ImageData from an image, for browser environments.
5
+ * This ImageData is then further processed to get QR codes.
6
+ * @param input - The image to get the ImageData from.
7
+ * @returns A promise that resolves to the ImageData.
8
+ */
9
+ export declare const getImageDataFromInput: (input: string | File | Uint8Array) => Promise<ImageData>;
10
+ /**
11
+ * Browser implementation of QR code library wrapper
12
+ */
13
+ export declare class BrowserQrCodeLib implements QrCodeLib {
14
+ private qrCodeModule;
15
+ /**
16
+ * Gets the QR code module, loading it if necessary
17
+ * @returns Promise that resolves to the QR code module
18
+ */
19
+ private getQrCodeModule;
20
+ /**
21
+ * @inheritdoc
22
+ */
23
+ toDataURL(text: string): Promise<string>;
24
+ getImageDataFromInput: (input: string | File | Uint8Array) => Promise<ImageData>;
25
+ }
@@ -0,0 +1,69 @@
1
+ import { TwoFALibError } from '../../TwoFALibError.mjs';
2
+ /**
3
+ * Gets the ImageData from an image, for browser environments.
4
+ * This ImageData is then further processed to get QR codes.
5
+ * @param input - The image to get the ImageData from.
6
+ * @returns A promise that resolves to the ImageData.
7
+ */
8
+ export const getImageDataFromInput = (input) => {
9
+ return new Promise((resolve, reject) => {
10
+ if (input instanceof Uint8Array) {
11
+ reject(new TwoFALibError('Uint8Array input not supported in browser environment'));
12
+ return;
13
+ }
14
+ const img = new Image();
15
+ img.onload = () => {
16
+ const canvas = document.createElement('canvas');
17
+ canvas.width = img.width;
18
+ canvas.height = img.height;
19
+ const ctx = canvas.getContext('2d');
20
+ if (!ctx) {
21
+ reject(new TwoFALibError('Could not create canvas context'));
22
+ return;
23
+ }
24
+ ctx.drawImage(img, 0, 0);
25
+ resolve(ctx.getImageData(0, 0, img.width, img.height));
26
+ };
27
+ img.onerror = () => reject(new TwoFALibError('Failed to load image'));
28
+ if (typeof input === 'string') {
29
+ // URL or Data URL
30
+ img.src = input;
31
+ }
32
+ else {
33
+ // File object
34
+ const reader = new FileReader();
35
+ reader.onload = (e) => {
36
+ img.src = e.target?.result;
37
+ };
38
+ reader.onerror = () => reject(new TwoFALibError('Failed to read file'));
39
+ reader.readAsDataURL(input);
40
+ }
41
+ });
42
+ };
43
+ /**
44
+ * Browser implementation of QR code library wrapper
45
+ */
46
+ export class BrowserQrCodeLib {
47
+ constructor() {
48
+ this.qrCodeModule = null;
49
+ this.getImageDataFromInput = getImageDataFromInput;
50
+ }
51
+ /**
52
+ * Gets the QR code module, loading it if necessary
53
+ * @returns Promise that resolves to the QR code module
54
+ */
55
+ async getQrCodeModule() {
56
+ if (!this.qrCodeModule) {
57
+ const qrcode = await import('qrcode');
58
+ this.qrCodeModule = qrcode.default;
59
+ }
60
+ return this.qrCodeModule;
61
+ }
62
+ /**
63
+ * @inheritdoc
64
+ */
65
+ async toDataURL(text) {
66
+ const qrCode = await this.getQrCodeModule();
67
+ return qrCode.toDataURL(text);
68
+ }
69
+ }
@@ -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 { generatePassphraseHash } from '../browser/index.mjs';
7
+ import { generatePassphraseHash } from '../browser/cryptoLib.mjs';
8
8
  const generateKeyPair = promisify(generateKeyPairCb);
9
9
  const generateKey = promisify(generateKeyCb);
10
10
  /**
@@ -0,0 +1,6 @@
1
+ import type { PlatformProviders } from '../../interfaces/PlatformProviders.mjs';
2
+ /**
3
+ * Node.js-specific platform providers
4
+ */
5
+ export declare const nodeProviders: PlatformProviders;
6
+ export default nodeProviders;
@@ -0,0 +1,13 @@
1
+ import NodeCryptoLib from './cryptoLib.mjs';
2
+ import { NodeQrCodeLib } from './qrCodeLib.mjs';
3
+ import { NodeOpenPgpLib } from './openPgpLib.mjs';
4
+ /**
5
+ * Node.js-specific platform providers
6
+ */
7
+ export const nodeProviders = {
8
+ CryptoLib: NodeCryptoLib,
9
+ WebSocketLib: () => WebSocket,
10
+ QrCodeLib: NodeQrCodeLib,
11
+ OpenPgpLib: NodeOpenPgpLib,
12
+ };
13
+ export default nodeProviders;
@@ -0,0 +1,20 @@
1
+ import type { OpenPgpLib } from '../../interfaces/OpenPgpLib.mjs';
2
+ /**
3
+ * Node.js implementation of OpenPGP library wrapper
4
+ */
5
+ export declare class NodeOpenPgpLib implements OpenPgpLib {
6
+ private openPgpModule;
7
+ /**
8
+ * Gets the OpenPGP module, loading it if necessary
9
+ * @returns Promise that resolves to the OpenPGP module
10
+ */
11
+ private getOpenPgpModule;
12
+ /**
13
+ * @inheritdoc
14
+ */
15
+ encrypt(data: string, password: string): Promise<string>;
16
+ /**
17
+ * @inheritdoc
18
+ */
19
+ decrypt(data: string, password: string): Promise<string>;
20
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Node.js implementation of OpenPGP library wrapper
3
+ */
4
+ export class NodeOpenPgpLib {
5
+ constructor() {
6
+ this.openPgpModule = null;
7
+ }
8
+ /**
9
+ * Gets the OpenPGP module, loading it if necessary
10
+ * @returns Promise that resolves to the OpenPGP module
11
+ */
12
+ async getOpenPgpModule() {
13
+ if (!this.openPgpModule) {
14
+ this.openPgpModule = await import('openpgp');
15
+ // enable Authenticated Encryption with Associated Data
16
+ this.openPgpModule.config.aeadProtect = true;
17
+ }
18
+ return this.openPgpModule;
19
+ }
20
+ /**
21
+ * @inheritdoc
22
+ */
23
+ async encrypt(data, password) {
24
+ const openPgp = await this.getOpenPgpModule();
25
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
26
+ const encrypted = await openPgp.encrypt({
27
+ message: await openPgp.createMessage({ text: data }),
28
+ passwords: [password],
29
+ format: 'armored',
30
+ });
31
+ return encrypted;
32
+ }
33
+ /**
34
+ * @inheritdoc
35
+ */
36
+ async decrypt(data, password) {
37
+ const openPgp = await this.getOpenPgpModule();
38
+ const decrypted = await openPgp.decrypt({
39
+ message: await openPgp.readMessage({ armoredMessage: data }),
40
+ passwords: [password],
41
+ });
42
+ return decrypted.data;
43
+ }
44
+ }
@@ -0,0 +1,28 @@
1
+ import type { ImageData } from 'canvas';
2
+ import type { QrCodeLib } from '../../interfaces/QrCodeLib.mjs';
3
+ /**
4
+ * Gets the ImageData from an image, for Node.js environments.
5
+ * This ImageData is then further processed to get QR codes.
6
+ * @param inputImage - The image to get the ImageData from.
7
+ * @returns A promise that resolves to the ImageData.
8
+ */
9
+ export declare const getImageDataFromInput: (inputImage: string | File | Uint8Array) => Promise<ImageData>;
10
+ /**
11
+ * Node.js implementation of QR code library wrapper
12
+ */
13
+ export declare class NodeQrCodeLib implements QrCodeLib {
14
+ private qrCodeModule;
15
+ /**
16
+ * Gets the QR code module, loading it if necessary
17
+ * @returns Promise that resolves to the QR code module
18
+ */
19
+ private getQrCodeModule;
20
+ /**
21
+ * @inheritdoc
22
+ */
23
+ toDataURL(text: string): Promise<string>;
24
+ /**
25
+ * @inheritdoc
26
+ */
27
+ getImageDataFromInput(imageInput: string | File | Uint8Array): Promise<ImageData>;
28
+ }
@@ -0,0 +1,54 @@
1
+ import { TwoFALibError } from '../../TwoFALibError.mjs';
2
+ import { isUint8Array } from 'uint8array-extras';
3
+ /**
4
+ * Gets the ImageData from an image, for Node.js environments.
5
+ * This ImageData is then further processed to get QR codes.
6
+ * @param inputImage - The image to get the ImageData from.
7
+ * @returns A promise that resolves to the ImageData.
8
+ */
9
+ export const getImageDataFromInput = async (inputImage) => {
10
+ if (inputImage instanceof File) {
11
+ throw new TwoFALibError('Getting data from QR where image type is "File" is not supported in the node environment');
12
+ }
13
+ const canvasLib = await import('canvas');
14
+ const { createCanvas, loadImage } = canvasLib;
15
+ // eslint-disable-next-line no-restricted-globals
16
+ const input = isUint8Array(inputImage) ? Buffer.from(inputImage) : inputImage;
17
+ const image = await loadImage(input); // canvaslib expects a buffer
18
+ const canvas = createCanvas(image.width, image.height);
19
+ const ctx = canvas.getContext('2d');
20
+ ctx.drawImage(image, 0, 0);
21
+ return ctx.getImageData(0, 0, image.width, image.height);
22
+ };
23
+ /**
24
+ * Node.js implementation of QR code library wrapper
25
+ */
26
+ export class NodeQrCodeLib {
27
+ constructor() {
28
+ this.qrCodeModule = null;
29
+ }
30
+ /**
31
+ * Gets the QR code module, loading it if necessary
32
+ * @returns Promise that resolves to the QR code module
33
+ */
34
+ async getQrCodeModule() {
35
+ if (!this.qrCodeModule) {
36
+ const qrcode = await import('qrcode');
37
+ this.qrCodeModule = qrcode.default;
38
+ }
39
+ return this.qrCodeModule;
40
+ }
41
+ /**
42
+ * @inheritdoc
43
+ */
44
+ async toDataURL(text) {
45
+ const qrCode = await this.getQrCodeModule();
46
+ return qrCode.toDataURL(text);
47
+ }
48
+ /**
49
+ * @inheritdoc
50
+ */
51
+ async getImageDataFromInput(imageInput) {
52
+ return getImageDataFromInput(imageInput);
53
+ }
54
+ }
@@ -51,7 +51,7 @@ class ExportImportManager {
51
51
  }
52
52
  if (passphrase) {
53
53
  await validatePassphraseStrength(this.libraryLoader, passphrase, this.passphraseExtraDict);
54
- return encryptExport(await this.libraryLoader.getOpenPGPLib(), exportData, passphrase);
54
+ return encryptExport(this.libraryLoader.getOpenPGPLib(), exportData, passphrase);
55
55
  }
56
56
  return exportData;
57
57
  }
@@ -59,7 +59,7 @@ class ExportImportManager {
59
59
  return generateTextExport(this.vaultDataManager.getAllEntries());
60
60
  }
61
61
  async generateHtmlExport() {
62
- const qrGeneratorLib = await this.libraryLoader.getQrGeneratorLib();
62
+ const qrGeneratorLib = this.libraryLoader.getQrGeneratorLib();
63
63
  return generateHtmlExport(qrGeneratorLib, this.vaultDataManager.getAllEntries());
64
64
  }
65
65
  /**
@@ -71,7 +71,7 @@ class ExportImportManager {
71
71
  */
72
72
  async importFromTextFile(fileContents, passphrase) {
73
73
  if (passphrase) {
74
- const decrypted = await decryptExport(await this.libraryLoader.getOpenPGPLib(), fileContents, passphrase);
74
+ const decrypted = await decryptExport(this.libraryLoader.getOpenPGPLib(), fileContents, passphrase);
75
75
  return this.importFromTextFile(decrypted);
76
76
  }
77
77
  const lines = fileContents.trim().split('\n');
@@ -1,52 +1,66 @@
1
1
  import type CryptoLib from '../interfaces/CryptoLib.mjs';
2
+ import type { PlatformProviders } from '../interfaces/PlatformProviders.mjs';
3
+ import type { QrCodeLib } from '../interfaces/QrCodeLib.mjs';
4
+ import type { OpenPgpLib } from '../interfaces/OpenPgpLib.mjs';
2
5
  /**
3
6
  * Class responsible for loading various external (big) libraries required by the application.
4
7
  * All libraries (except CryptoLib) are loaded on demand. This helps to reduce the initial bundle size.
5
8
  */
6
9
  declare class LibraryLoader {
10
+ private platformProviders;
7
11
  private cryptoLib;
8
12
  private openPgpLib?;
9
13
  private qrGeneratorLib?;
10
14
  private jsQrLib?;
11
- private canvasLib?;
12
15
  private urlParserLib?;
13
16
  private zxcvbn?;
17
+ private webSocketLib?;
14
18
  /**
15
19
  * Constructs a new instance of LibraryLoader.
16
- * @param cryptoLib - An instance of CryptoLib that is required for library operations.
17
- * @throws {InitializationError} If the provided CryptoLib instance is invalid.
20
+ * @param platformProviders - Platform-specific providers containing CryptoLib and other providers.
21
+ * @throws {InitializationError} If the provided platform providers are invalid.
18
22
  */
19
- constructor(cryptoLib: CryptoLib);
23
+ constructor(platformProviders: PlatformProviders);
20
24
  /**
21
25
  * @returns The CryptoLib instance.
22
26
  */
23
27
  getCryptoLib(): CryptoLib;
28
+ /**
29
+ * @returns The PlatformProviders instance.
30
+ */
31
+ getPlatformProviders(): PlatformProviders;
24
32
  /**
25
33
  * Loads and returns the OpenPGP library on demand.
26
34
  * @returns A promise that resolves to the OpenPGP library.
27
35
  */
28
- getOpenPGPLib(): Promise<typeof import("openpgp")>;
36
+ getOpenPGPLib(): OpenPgpLib;
29
37
  /**
30
38
  * Loads and returns the QR Generator library on demand.
31
39
  * @returns A promise that resolves to the QR Generator library.
32
40
  */
33
- getQrGeneratorLib(): Promise<typeof import("qrcode")>;
41
+ getQrGeneratorLib(): QrCodeLib;
34
42
  /**
35
43
  * Loads and returns the JsQR library on demand.
36
44
  * @returns A promise that resolves to the JsQR library.
37
45
  */
38
46
  getJsQrLib(): Promise<typeof import("jsqr").default>;
39
- /**
40
- * Loads and returns the Canvas library on demand.
41
- * @returns A promise that resolves to the Canvas library.
42
- * @throws {TwoFALibError} If the library cannot be loaded in a browser environment.
43
- */
44
- getCanvasLib(): Promise<typeof import("canvas")>;
45
47
  /**
46
48
  * Loads and returns the URL Parser library on demand.
47
49
  * @returns A promise that resolves to the URL Parser library.
48
50
  */
49
51
  getUrlParserLib(): Promise<typeof import("whatwg-url")>;
52
+ /**
53
+ * Loads and returns the WebSocket library on demand.
54
+ * @returns The WebSocket library.
55
+ */
56
+ getWebSocketLib(): {
57
+ new (url: string | URL, protocols?: string | string[]): WebSocket;
58
+ prototype: WebSocket;
59
+ readonly CONNECTING: 0;
60
+ readonly OPEN: 1;
61
+ readonly CLOSING: 2;
62
+ readonly CLOSED: 3;
63
+ };
50
64
  /**
51
65
  * Loads and returns the Zxcvbn library on demand.
52
66
  * @returns A promise that resolves to the Zxcvbn library.
@@ -1,4 +1,4 @@
1
- import { InitializationError, TwoFALibError } from '../TwoFALibError.mjs';
1
+ import { InitializationError } from '../TwoFALibError.mjs';
2
2
  /**
3
3
  * Class responsible for loading various external (big) libraries required by the application.
4
4
  * All libraries (except CryptoLib) are loaded on demand. This helps to reduce the initial bundle size.
@@ -6,14 +6,15 @@ import { InitializationError, TwoFALibError } from '../TwoFALibError.mjs';
6
6
  class LibraryLoader {
7
7
  /**
8
8
  * Constructs a new instance of LibraryLoader.
9
- * @param cryptoLib - An instance of CryptoLib that is required for library operations.
10
- * @throws {InitializationError} If the provided CryptoLib instance is invalid.
9
+ * @param platformProviders - Platform-specific providers containing CryptoLib and other providers.
10
+ * @throws {InitializationError} If the provided platform providers are invalid.
11
11
  */
12
- constructor(cryptoLib) {
13
- if (!cryptoLib) {
14
- throw new InitializationError('CryptoLib is required');
12
+ constructor(platformProviders) {
13
+ if (!platformProviders?.CryptoLib) {
14
+ throw new InitializationError('PlatformProviders with CryptoLib is required');
15
15
  }
16
- this.cryptoLib = cryptoLib;
16
+ this.platformProviders = platformProviders;
17
+ this.cryptoLib = new platformProviders.CryptoLib();
17
18
  }
18
19
  /**
19
20
  * @returns The CryptoLib instance.
@@ -21,28 +22,26 @@ class LibraryLoader {
21
22
  getCryptoLib() {
22
23
  return this.cryptoLib;
23
24
  }
25
+ /**
26
+ * @returns The PlatformProviders instance.
27
+ */
28
+ getPlatformProviders() {
29
+ return this.platformProviders;
30
+ }
24
31
  /**
25
32
  * Loads and returns the OpenPGP library on demand.
26
33
  * @returns A promise that resolves to the OpenPGP library.
27
34
  */
28
- async getOpenPGPLib() {
29
- if (!this.openPgpLib) {
30
- const module = await import('openpgp');
31
- // enable Authenticated Encryption with Associated Data
32
- module.config.aeadProtect = true;
33
- this.openPgpLib = module;
34
- }
35
+ getOpenPGPLib() {
36
+ this.openPgpLib ??= new this.platformProviders.OpenPgpLib();
35
37
  return this.openPgpLib;
36
38
  }
37
39
  /**
38
40
  * Loads and returns the QR Generator library on demand.
39
41
  * @returns A promise that resolves to the QR Generator library.
40
42
  */
41
- async getQrGeneratorLib() {
42
- if (!this.qrGeneratorLib) {
43
- const module = await import('qrcode');
44
- this.qrGeneratorLib = module.default;
45
- }
43
+ getQrGeneratorLib() {
44
+ this.qrGeneratorLib ??= new this.platformProviders.QrCodeLib();
46
45
  return this.qrGeneratorLib;
47
46
  }
48
47
  /**
@@ -56,21 +55,6 @@ class LibraryLoader {
56
55
  }
57
56
  return this.jsQrLib;
58
57
  }
59
- /**
60
- * Loads and returns the Canvas library on demand.
61
- * @returns A promise that resolves to the Canvas library.
62
- * @throws {TwoFALibError} If the library cannot be loaded in a browser environment.
63
- */
64
- async getCanvasLib() {
65
- if (typeof window !== 'undefined') {
66
- throw new TwoFALibError('Canvas lib can not be loaded in browser env');
67
- }
68
- if (!this.canvasLib) {
69
- const module = await import('canvas');
70
- this.canvasLib = module.default;
71
- }
72
- return this.canvasLib;
73
- }
74
58
  /**
75
59
  * Loads and returns the URL Parser library on demand.
76
60
  * @returns A promise that resolves to the URL Parser library.
@@ -82,6 +66,14 @@ class LibraryLoader {
82
66
  }
83
67
  return this.urlParserLib;
84
68
  }
69
+ /**
70
+ * Loads and returns the WebSocket library on demand.
71
+ * @returns The WebSocket library.
72
+ */
73
+ getWebSocketLib() {
74
+ this.webSocketLib ??= this.platformProviders.WebSocketLib();
75
+ return this.webSocketLib;
76
+ }
85
77
  /**
86
78
  * Loads and returns the Zxcvbn library on demand.
87
79
  * @returns A promise that resolves to the Zxcvbn library.
@@ -141,12 +141,13 @@ class SyncManager {
141
141
  * Initializes the WebSocket connection to the server.
142
142
  */
143
143
  initServerConnection() {
144
- const ws = new WebSocket(this.serverUrl);
144
+ const WebSocketLib = this.libraryLoader.getWebSocketLib();
145
+ const ws = new WebSocketLib(this.serverUrl);
145
146
  // eslint-disable-next-line @typescript-eslint/no-this-alias
146
147
  const syncManager = this;
147
- ws.addEventListener('error', (event) => {
148
- // eslint-disable-next-line @typescript-eslint/no-base-to-string
149
- syncManager.log('warning', `Error in websocket: ${event.toString()}`);
148
+ ws.addEventListener('error', () => {
149
+ // no error information seems to be available...
150
+ syncManager.log('warning', `Error in websocket.`);
150
151
  });
151
152
  ws.addEventListener('message', function message(message) {
152
153
  try {
@@ -326,7 +327,7 @@ class SyncManager {
326
327
  };
327
328
  let returnQr = null;
328
329
  if (returnAs.qr) {
329
- const qrGeneratorLib = await this.libraryLoader.getQrGeneratorLib();
330
+ const qrGeneratorLib = this.libraryLoader.getQrGeneratorLib();
330
331
  returnQr = await qrGeneratorLib.toDataURL(JSON.stringify(returnData));
331
332
  }
332
333
  const returnText = returnAs.text
@@ -352,7 +353,7 @@ class SyncManager {
352
353
  if (this.activeAddDeviceFlow) {
353
354
  throw new SyncAddDeviceFlowConflictError();
354
355
  }
355
- const { addDevicePassword, initiatorDeviceId, timestamp, pass1Result } = await decodeInitiatorData(initiatorData, initiatorDataType, await this.libraryLoader.getJsQrLib(), this.libraryLoader.getCanvasLib.bind(this));
356
+ const { addDevicePassword, initiatorDeviceId, timestamp, pass1Result } = await decodeInitiatorData(initiatorData, initiatorDataType, await this.libraryLoader.getJsQrLib(), this.libraryLoader.getQrGeneratorLib());
356
357
  if (!addDevicePassword ||
357
358
  !initiatorDeviceId ||
358
359
  !timestamp ||
@@ -1,5 +1,5 @@
1
1
  import type { ZxcvbnResult } from '@zxcvbn-ts/core';
2
- import type CryptoLib from '../interfaces/CryptoLib.mjs';
2
+ import type { PlatformProviders } from '../interfaces/PlatformProviders.mjs';
3
3
  import type { Passphrase } from '../interfaces/CryptoLib.mjs';
4
4
  import type { DeviceType } from '../interfaces/SyncTypes.mjs';
5
5
  import TwoFaLib from '../TwoFaLib.mjs';
@@ -25,14 +25,14 @@ export declare const getPassphraseStrength: (libraryLoader: LibraryLoader, passp
25
25
  export declare const validatePassphraseStrength: (libraryLoader: LibraryLoader, passphrase: Passphrase, passphraseExtraDict: PassphraseExtraDict) => Promise<void>;
26
26
  /**
27
27
  * Returns utility functions useful in creating a new twoFaLib vault
28
- * @param cryptoLib - An instance of CryptoLib that is compatible with the environment.
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
30
  * @param passphraseExtraDict - Additional words to be used for passphrase strength evaluation.
31
31
  * @param saveFunction - The function to save the data.
32
32
  * @param serverUrl - The server URL for syncing.
33
33
  * @returns An object with methods to evaluate passphrase strength and create a new TwoFaLib vault.
34
34
  */
35
- export declare const getTwoFaLibVaultCreationUtils: (cryptoLib: CryptoLib, deviceType: DeviceType, passphraseExtraDict: PassphraseExtraDict, saveFunction?: SaveFunction, serverUrl?: string) => {
35
+ export declare const getTwoFaLibVaultCreationUtils: (platformProviders: PlatformProviders, deviceType: DeviceType, passphraseExtraDict: PassphraseExtraDict, saveFunction?: SaveFunction, serverUrl?: string) => {
36
36
  getPassphraseStrength: (passphrase: Passphrase, passphraseExtraDict: PassphraseExtraDict) => Promise<ZxcvbnResult>;
37
37
  createNewTwoFaLibVault: (passphrase: Passphrase) => Promise<{
38
38
  twoFaLib: TwoFaLib;
@@ -62,10 +62,11 @@ export const validatePassphraseStrength = async (libraryLoader, passphrase, pass
62
62
  */
63
63
  const createNewTwoFaLibVault = async (libraryLoader, deviceType, serverUrl, passphraseExtraDict, saveFunction, passphrase) => {
64
64
  const cryptoLib = libraryLoader.getCryptoLib();
65
+ const platformProviders = libraryLoader.getPlatformProviders();
65
66
  const { publicKey, privateKey, symmetricKey, encryptedPrivateKey, encryptedSymmetricKey, salt, } = await cryptoLib.createKeys(passphrase);
66
67
  await validatePassphraseStrength(libraryLoader, passphrase, passphraseExtraDict);
67
68
  const deviceId = genUuidV4();
68
- const twoFaLib = new TwoFaLib(deviceType, cryptoLib, passphraseExtraDict, privateKey, symmetricKey, encryptedPrivateKey, encryptedSymmetricKey, salt, publicKey, {
69
+ const twoFaLib = new TwoFaLib(deviceType, platformProviders, passphraseExtraDict, privateKey, symmetricKey, encryptedPrivateKey, encryptedSymmetricKey, salt, publicKey, {
69
70
  deviceId,
70
71
  }, [], saveFunction, {
71
72
  serverUrl,
@@ -93,6 +94,7 @@ const createNewTwoFaLibVault = async (libraryLoader, deviceType, serverUrl, pass
93
94
  */
94
95
  const loadTwoFaLibFromLockedRepesentation = async (libraryLoader, deviceType, passphraseExtraDict, saveFunction, lockedRepresentationString, passphrase) => {
95
96
  const cryptoLib = libraryLoader.getCryptoLib();
97
+ const platformProviders = libraryLoader.getPlatformProviders();
96
98
  const lockedRepresentation = JSON.parse(lockedRepresentationString);
97
99
  if (!lockedRepresentation ||
98
100
  !lockedRepresentation.encryptedPrivateKey ||
@@ -109,22 +111,22 @@ const loadTwoFaLibFromLockedRepesentation = async (libraryLoader, deviceType, pa
109
111
  !vaultState.sync?.devices) {
110
112
  throw new InitializationError('encryptedVaultState is incomplete or corrupted');
111
113
  }
112
- return new TwoFaLib(deviceType, cryptoLib, passphraseExtraDict, privateKey, symmetricKey, lockedRepresentation.encryptedPrivateKey, lockedRepresentation.encryptedSymmetricKey, lockedRepresentation.salt, publicKey, {
114
+ return new TwoFaLib(deviceType, platformProviders, passphraseExtraDict, privateKey, symmetricKey, lockedRepresentation.encryptedPrivateKey, lockedRepresentation.encryptedSymmetricKey, lockedRepresentation.salt, publicKey, {
113
115
  deviceId: vaultState.deviceId,
114
116
  deviceFriendlyName: vaultState.deviceFriendlyName,
115
117
  }, vaultState.vault, saveFunction, vaultState.sync);
116
118
  };
117
119
  /**
118
120
  * Returns utility functions useful in creating a new twoFaLib vault
119
- * @param cryptoLib - An instance of CryptoLib that is compatible with the environment.
121
+ * @param platformProviders - The platform-specific providers containing CryptoLib and other providers.
120
122
  * @param deviceType - A unique identifier for this device type (e.g. 2fa-cli).
121
123
  * @param passphraseExtraDict - Additional words to be used for passphrase strength evaluation.
122
124
  * @param saveFunction - The function to save the data.
123
125
  * @param serverUrl - The server URL for syncing.
124
126
  * @returns An object with methods to evaluate passphrase strength and create a new TwoFaLib vault.
125
127
  */
126
- export const getTwoFaLibVaultCreationUtils = (cryptoLib, deviceType, passphraseExtraDict, saveFunction, serverUrl) => {
127
- const libraryLoader = new LibraryLoader(cryptoLib);
128
+ export const getTwoFaLibVaultCreationUtils = (platformProviders, deviceType, passphraseExtraDict, saveFunction, serverUrl) => {
129
+ const libraryLoader = new LibraryLoader(platformProviders);
128
130
  return {
129
131
  getPassphraseStrength: getPassphraseStrength.bind(null, libraryLoader),
130
132
  createNewTwoFaLibVault: createNewTwoFaLibVault.bind(null, libraryLoader, deviceType, serverUrl, passphraseExtraDict, saveFunction),
@@ -1,6 +1,8 @@
1
1
  import type { NewEntry } from '../interfaces/Entry.mjs';
2
2
  import type Entry from '../interfaces/Entry.mjs';
3
3
  import type { EntryId } from '../interfaces/Entry.mjs';
4
+ import type { QrCodeLib } from '../interfaces/QrCodeLib.mjs';
5
+ import type { OpenPgpLib } from '../interfaces/OpenPgpLib.mjs';
4
6
  /**
5
7
  * Parses an OTP URI and extracts the relevant information to create a new entry.
6
8
  * @param UrlParser - The URL parsing library.
@@ -15,7 +17,7 @@ export declare const parseOtpUri: (UrlParser: typeof import("whatwg-url"), otpUr
15
17
  * @param entries - An array of OTP entries.
16
18
  * @returns A promise that resolves to the HTML string.
17
19
  */
18
- export declare const generateHtmlExport: (qrGeneratorLib: typeof import("qrcode"), entries: Entry[]) => Promise<string>;
20
+ export declare const generateHtmlExport: (qrGeneratorLib: QrCodeLib, entries: Entry[]) => Promise<string>;
19
21
  /**
20
22
  * Generates a text export of OTP URIs for the provided entries.
21
23
  * @param entries - An array of OTP entries.
@@ -42,7 +44,7 @@ export declare const processImportLines: (lines: string[], importFromUri: (uri:
42
44
  * @param password - The password to use for encryption.
43
45
  * @returns A promise that resolves to the encrypted data.
44
46
  */
45
- export declare const encryptExport: (openPgpLib: typeof import("openpgp"), data: string, password: string) => Promise<string>;
47
+ export declare const encryptExport: (openPgpLib: OpenPgpLib, data: string, password: string) => Promise<string>;
46
48
  /**
47
49
  * Decrypts the given data using OpenPGP.
48
50
  * @param openPgpLib - The OpenPGP library.
@@ -50,4 +52,4 @@ export declare const encryptExport: (openPgpLib: typeof import("openpgp"), data:
50
52
  * @param password - The password to use for decryption.
51
53
  * @returns A promise that resolves to the decrypted data.
52
54
  */
53
- export declare const decryptExport: (openPgpLib: typeof import("openpgp"), data: string, password: string) => Promise<string>;
55
+ export declare const decryptExport: (openPgpLib: OpenPgpLib, data: string, password: string) => Promise<string>;
@@ -162,13 +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
166
- const encrypted = await openPgpLib.encrypt({
167
- message: await openPgpLib.createMessage({ text: data }),
168
- passwords: [password],
169
- format: 'armored',
170
- });
171
- return encrypted;
165
+ return openPgpLib.encrypt(data, password);
172
166
  };
173
167
  /**
174
168
  * Decrypts the given data using OpenPGP.
@@ -178,9 +172,5 @@ export const encryptExport = async (openPgpLib, data, password) => {
178
172
  * @returns A promise that resolves to the decrypted data.
179
173
  */
180
174
  export const decryptExport = async (openPgpLib, data, password) => {
181
- const decrypted = await openPgpLib.decrypt({
182
- message: await openPgpLib.readMessage({ armoredMessage: data }),
183
- passwords: [password],
184
- });
185
- return decrypted.data;
175
+ return openPgpLib.decrypt(data, password);
186
176
  };
@@ -1,20 +1,4 @@
1
- import type { ImageData } from 'canvas';
2
1
  import LibraryLoader from '../subclasses/LibraryLoader.mjs';
3
- /**
4
- * Gets the ImageData from an image, for browser environments.
5
- * This ImageData is then further processed to get QR codes.
6
- * @param input - The image to get the ImageData from.
7
- * @returns A promise that resolves to the ImageData.
8
- */
9
- export declare const getImageDataBrowser: (input: string | File) => Promise<ImageData>;
10
- /**
11
- * Gets the ImageData from an image, for Node.js environments.
12
- * This ImageData is then further processed to get QR codes.
13
- * @param canvasLib - The Canvas library.
14
- * @param inputImage - The image to get the ImageData from.
15
- * @returns A promise that resolves to the ImageData.
16
- */
17
- export declare const getImageDataNode: (canvasLib: typeof import("canvas"), inputImage: Uint8Array | string) => Promise<ImageData>;
18
2
  /**
19
3
  * Import an entry from a QR code image.
20
4
  * @param libraryLoader - An instance of LibraryLoader.
@@ -1,59 +1,4 @@
1
- import { isUint8Array } from 'uint8array-extras';
2
1
  import { TwoFALibError } from '../TwoFALibError.mjs';
3
- /**
4
- * Gets the ImageData from an image, for browser environments.
5
- * This ImageData is then further processed to get QR codes.
6
- * @param input - The image to get the ImageData from.
7
- * @returns A promise that resolves to the ImageData.
8
- */
9
- export const getImageDataBrowser = (input) => {
10
- return new Promise((resolve, reject) => {
11
- const img = new Image();
12
- img.onload = () => {
13
- const canvas = document.createElement('canvas');
14
- canvas.width = img.width;
15
- canvas.height = img.height;
16
- const ctx = canvas.getContext('2d');
17
- if (!ctx) {
18
- reject(new TwoFALibError('Could not create canvas context'));
19
- return;
20
- }
21
- ctx.drawImage(img, 0, 0);
22
- resolve(ctx.getImageData(0, 0, img.width, img.height));
23
- };
24
- img.onerror = () => reject(new TwoFALibError('Failed to load image'));
25
- if (typeof input === 'string') {
26
- // URL or Data URL
27
- img.src = input;
28
- }
29
- else {
30
- // File object
31
- const reader = new FileReader();
32
- reader.onload = (e) => {
33
- img.src = e.target?.result;
34
- };
35
- reader.onerror = () => reject(new TwoFALibError('Failed to read file'));
36
- reader.readAsDataURL(input);
37
- }
38
- });
39
- };
40
- /**
41
- * Gets the ImageData from an image, for Node.js environments.
42
- * This ImageData is then further processed to get QR codes.
43
- * @param canvasLib - The Canvas library.
44
- * @param inputImage - The image to get the ImageData from.
45
- * @returns A promise that resolves to the ImageData.
46
- */
47
- export const getImageDataNode = async (canvasLib, inputImage) => {
48
- const { createCanvas, loadImage } = canvasLib;
49
- // eslint-disable-next-line no-restricted-globals
50
- const input = isUint8Array(inputImage) ? Buffer.from(inputImage) : inputImage;
51
- const image = await loadImage(input); // canvaslib expects a buffer
52
- const canvas = createCanvas(image.width, image.height);
53
- const ctx = canvas.getContext('2d');
54
- ctx.drawImage(image, 0, 0);
55
- return ctx.getImageData(0, 0, image.width, image.height);
56
- };
57
2
  /**
58
3
  * Import an entry from a QR code image.
59
4
  * @param libraryLoader - An instance of LibraryLoader.
@@ -63,19 +8,8 @@ export const getImageDataNode = async (canvasLib, inputImage) => {
63
8
  */
64
9
  export const getDataFromQRImage = async (libraryLoader, imageInput) => {
65
10
  const jsQr = await libraryLoader.getJsQrLib();
66
- let imageData;
67
- if (typeof window !== 'undefined') {
68
- // Browser environment
69
- imageData = await getImageDataBrowser(imageInput);
70
- }
71
- else {
72
- if (imageInput instanceof File) {
73
- throw new TwoFALibError('Getting data from QR where image type is "File" is not supported in the node environment');
74
- }
75
- // Node.js environment
76
- const canvasLib = await libraryLoader.getCanvasLib();
77
- imageData = await getImageDataNode(canvasLib, imageInput);
78
- }
11
+ const qrLib = libraryLoader.getQrGeneratorLib();
12
+ const imageData = await qrLib.getImageDataFromInput(imageInput);
79
13
  const qrCodeResult = jsQr(imageData.data, imageData.width, imageData.height);
80
14
  if (!qrCodeResult) {
81
15
  throw new TwoFALibError("Couldn't read QR code data from image");
@@ -1,13 +1,14 @@
1
1
  import { InitiateAddDeviceFlowResult } from '../interfaces/SyncTypes.mjs';
2
+ import type { QrCodeLib } from '../interfaces/QrCodeLib.mjs';
2
3
  /**
3
4
  * Decodes the initiator data from a string or QR code.
4
5
  * @param initiatorData - The initiator data to decode.
5
6
  * @param initiatorDataType The type of the initiatorData, determines how it should be decoded
6
7
  * @param jsQr - The QR code decoder.
7
- * @param getCanvasLib - A function to get the Canvas library.
8
+ * @param qrCodeLib - The extended QR code library with platform-specific image processing.
8
9
  * @returns A promise that resolves to the decoded initiator data.
9
10
  */
10
- export declare const decodeInitiatorData: (initiatorData: string | Uint8Array | File, initiatorDataType: "text" | "qr", jsQr: typeof import("jsqr").default, getCanvasLib: () => Promise<typeof import("canvas")>) => Promise<InitiateAddDeviceFlowResult>;
11
+ export declare const decodeInitiatorData: (initiatorData: string | Uint8Array | File, initiatorDataType: "text" | "qr", jsQr: typeof import("jsqr").default, qrCodeLib: QrCodeLib) => Promise<InitiateAddDeviceFlowResult>;
11
12
  /**
12
13
  * Converts a JSONified Uint8Array to a Uint8Array.
13
14
  * A JSONified Uint8Array is the output of JSON.stringify on a Uint8Array.
@@ -1,33 +1,17 @@
1
1
  import { base64ToString } from 'uint8array-extras';
2
- import { getImageDataBrowser, getImageDataNode } from './qrUtils.mjs';
3
2
  import { SyncError } from '../TwoFALibError.mjs';
4
3
  /**
5
4
  * Decodes the initiator data from a string or QR code.
6
5
  * @param initiatorData - The initiator data to decode.
7
6
  * @param initiatorDataType The type of the initiatorData, determines how it should be decoded
8
7
  * @param jsQr - The QR code decoder.
9
- * @param getCanvasLib - A function to get the Canvas library.
8
+ * @param qrCodeLib - The extended QR code library with platform-specific image processing.
10
9
  * @returns A promise that resolves to the decoded initiator data.
11
10
  */
12
- export const decodeInitiatorData = async (initiatorData, initiatorDataType, jsQr, getCanvasLib) => {
11
+ export const decodeInitiatorData = async (initiatorData, initiatorDataType, jsQr, qrCodeLib) => {
13
12
  if (initiatorDataType === 'qr') {
14
13
  try {
15
- let imageData;
16
- if (typeof window !== 'undefined') {
17
- if (initiatorData instanceof Uint8Array) {
18
- throw new SyncError('Invalid initiator data type, should be a string or File in browser environment');
19
- }
20
- // Browser environment
21
- imageData = await getImageDataBrowser(initiatorData);
22
- }
23
- else {
24
- if (!(initiatorData instanceof Uint8Array)) {
25
- throw new SyncError('Invalid initiator data type, should be a Uint8Array in Node.js environment');
26
- }
27
- // Node.js environment
28
- const canvasLib = await getCanvasLib();
29
- imageData = await getImageDataNode(canvasLib, initiatorData);
30
- }
14
+ const imageData = await qrCodeLib.getImageDataFromInput(initiatorData);
31
15
  const qrCodeResult = jsQr(imageData.data, imageData.width, imageData.height);
32
16
  if (!qrCodeResult) {
33
17
  throw new SyncError('Invalid QR code');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "favalib",
3
- "version": "0.0.11",
3
+ "version": "0.0.12",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "exports": {
@@ -8,13 +8,13 @@
8
8
  "import": "./build/main.mjs",
9
9
  "types": "./build/main.d.mts"
10
10
  },
11
- "./cryptoProviders/browser": {
12
- "import": "./build/CryptoProviders/browser/index.mjs",
13
- "types": "./build/CryptoProviders/browser/index.d.mts"
11
+ "./platformProviders/browser": {
12
+ "import": "./build/platformProviders/browser/index.mjs",
13
+ "types": "./build/platformProviders/browser/index.d.mts"
14
14
  },
15
- "./cryptoProviders/node": {
16
- "import": "./build/CryptoProviders/node/index.mjs",
17
- "types": "./build/CryptoProviders/node/index.d.mts"
15
+ "./platformProviders/node": {
16
+ "import": "./build/platformProviders/node/index.mjs",
17
+ "types": "./build/platformProviders/node/index.d.mts"
18
18
  }
19
19
  },
20
20
  "types": "./build/main.d.mts",
@@ -39,6 +39,7 @@
39
39
  "@zxcvbn-ts/language-common": "^3.0.4",
40
40
  "@zxcvbn-ts/language-en": "^3.0.2",
41
41
  "canvas": "^3.1.0",
42
+ "esbuild": "^0.25.8",
42
43
  "hash-wasm": "^4.12.0",
43
44
  "jpake-ts": "^1.0.1",
44
45
  "jsqr": "^1.4.0",
@@ -48,7 +49,6 @@
48
49
  "totp-generator": "^1.0.0",
49
50
  "typescript-event-target": "^1.1.1",
50
51
  "uint8array-extras": "^1.4.0",
51
- "unws": "^0.3.2",
52
52
  "uuid": "^11.1.0",
53
53
  "whatwg-url": "^14.2.0",
54
54
  "ws": "^8.18.2"