favalib 0.0.10 → 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.
- package/build/Command/commandConstructors.d.mts +2 -2
- package/build/Command/commandConstructors.mjs +2 -2
- package/build/Command/commands/ChangeDeviceInfoCommand.d.mts +6 -6
- package/build/Command/commands/ChangeDeviceInfoCommand.mjs +3 -3
- package/build/TwoFaLib.d.mts +3 -3
- package/build/TwoFaLib.mjs +16 -12
- package/build/interfaces/CommandTypes.d.mts +4 -4
- package/build/interfaces/OpenPgpLib.d.mts +20 -0
- package/build/interfaces/OpenPgpLib.mjs +1 -0
- package/build/interfaces/PlatformProviders.d.mts +26 -0
- package/build/interfaces/PlatformProviders.mjs +1 -0
- package/build/interfaces/QrCodeLib.d.mts +19 -0
- package/build/interfaces/QrCodeLib.mjs +1 -0
- package/build/main.d.mts +2 -1
- package/build/platformProviders/browser/index.d.mts +6 -0
- package/build/platformProviders/browser/index.mjs +13 -0
- package/build/platformProviders/browser/openPgpLib.d.mts +20 -0
- package/build/platformProviders/browser/openPgpLib.mjs +44 -0
- package/build/platformProviders/browser/qrCodeLib.d.mts +25 -0
- package/build/platformProviders/browser/qrCodeLib.mjs +69 -0
- package/build/{CryptoProviders/node/index.mjs → platformProviders/node/cryptoLib.mjs} +1 -1
- package/build/platformProviders/node/index.d.mts +6 -0
- package/build/platformProviders/node/index.mjs +13 -0
- package/build/platformProviders/node/openPgpLib.d.mts +20 -0
- package/build/platformProviders/node/openPgpLib.mjs +44 -0
- package/build/platformProviders/node/qrCodeLib.d.mts +28 -0
- package/build/platformProviders/node/qrCodeLib.mjs +54 -0
- package/build/subclasses/ExportImportManager.mjs +3 -3
- package/build/subclasses/LibraryLoader.d.mts +26 -12
- package/build/subclasses/LibraryLoader.mjs +26 -34
- package/build/subclasses/SyncManager.mjs +7 -6
- package/build/utils/creationUtils.d.mts +3 -3
- package/build/utils/creationUtils.mjs +7 -5
- package/build/utils/exportImportUtils.d.mts +5 -3
- package/build/utils/exportImportUtils.mjs +2 -12
- package/build/utils/qrUtils.d.mts +0 -16
- package/build/utils/qrUtils.mjs +2 -68
- package/build/utils/syncUtils.d.mts +3 -2
- package/build/utils/syncUtils.mjs +3 -19
- package/package.json +8 -8
- /package/build/{CryptoProviders/browser/index.d.mts → platformProviders/browser/cryptoLib.d.mts} +0 -0
- /package/build/{CryptoProviders/browser/index.mjs → platformProviders/browser/cryptoLib.mjs} +0 -0
- /package/build/{CryptoProviders/node/index.d.mts → platformProviders/node/cryptoLib.d.mts} +0 -0
|
@@ -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(
|
|
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 =
|
|
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(
|
|
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
|
|
17
|
-
* @throws {InitializationError} If the provided
|
|
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(
|
|
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():
|
|
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():
|
|
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
|
|
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
|
|
10
|
-
* @throws {InitializationError} If the provided
|
|
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(
|
|
13
|
-
if (!
|
|
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.
|
|
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
|
-
|
|
29
|
-
|
|
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
|
-
|
|
42
|
-
|
|
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
|
|
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', (
|
|
148
|
-
//
|
|
149
|
-
syncManager.log('warning', `Error in websocket
|
|
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 =
|
|
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.
|
|
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
|
|
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
|
|
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: (
|
|
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,
|
|
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,
|
|
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
|
|
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 = (
|
|
127
|
-
const libraryLoader = new LibraryLoader(
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
package/build/utils/qrUtils.mjs
CHANGED
|
@@ -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
|
-
|
|
67
|
-
|
|
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
|
|
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,
|
|
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
|
|
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,
|
|
11
|
+
export const decodeInitiatorData = async (initiatorData, initiatorDataType, jsQr, qrCodeLib) => {
|
|
13
12
|
if (initiatorDataType === 'qr') {
|
|
14
13
|
try {
|
|
15
|
-
|
|
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.
|
|
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
|
-
"./
|
|
12
|
-
"import": "./build/
|
|
13
|
-
"types": "./build/
|
|
11
|
+
"./platformProviders/browser": {
|
|
12
|
+
"import": "./build/platformProviders/browser/index.mjs",
|
|
13
|
+
"types": "./build/platformProviders/browser/index.d.mts"
|
|
14
14
|
},
|
|
15
|
-
"./
|
|
16
|
-
"import": "./build/
|
|
17
|
-
"types": "./build/
|
|
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"
|
/package/build/{CryptoProviders/browser/index.d.mts → platformProviders/browser/cryptoLib.d.mts}
RENAMED
|
File without changes
|
/package/build/{CryptoProviders/browser/index.mjs → platformProviders/browser/cryptoLib.mjs}
RENAMED
|
File without changes
|
|
File without changes
|