favalib 0.0.9 → 0.0.11
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/AddSyncDeviceCommand.d.mts +2 -1
- package/build/Command/commands/ChangeDeviceInfoCommand.d.mts +37 -0
- package/build/Command/commands/ChangeDeviceInfoCommand.mjs +78 -0
- package/build/TwoFaLib.d.mts +8 -3
- package/build/TwoFaLib.mjs +21 -5
- package/build/interfaces/CommandTypes.d.mts +4 -4
- package/build/interfaces/SyncTypes.d.mts +15 -6
- package/build/main.d.mts +2 -2
- package/build/subclasses/PersistentStorageManager.d.mts +4 -2
- package/build/subclasses/PersistentStorageManager.mjs +3 -1
- package/build/subclasses/SyncManager.d.mts +9 -11
- package/build/subclasses/SyncManager.mjs +47 -36
- package/package.json +1 -1
- package/build/Command/commands/ChangeSyncDeviceMetaCommand.d.mts +0 -32
- package/build/Command/commands/ChangeSyncDeviceMetaCommand.mjs +0 -37
|
@@ -2,12 +2,12 @@ import AddEntryCommand from './commands/AddEntryCommand.mjs';
|
|
|
2
2
|
import AddSyncDeviceCommand from './commands/AddSyncDeviceCommand.mjs';
|
|
3
3
|
import DeleteEntryCommand from './commands/DeleteEntryCommand.mjs';
|
|
4
4
|
import UpdateEntryCommand from './commands/UpdateEntryCommand.mjs';
|
|
5
|
-
import
|
|
5
|
+
import ChangeDeviceInfoCommand from './commands/ChangeDeviceInfoCommand.mjs';
|
|
6
6
|
declare const commandConstructors: {
|
|
7
7
|
AddEntry: typeof AddEntryCommand;
|
|
8
8
|
DeleteEntry: typeof DeleteEntryCommand;
|
|
9
9
|
UpdateEntry: typeof UpdateEntryCommand;
|
|
10
10
|
AddSyncDevice: typeof AddSyncDeviceCommand;
|
|
11
|
-
|
|
11
|
+
ChangeDeviceInfo: typeof ChangeDeviceInfoCommand;
|
|
12
12
|
};
|
|
13
13
|
export default commandConstructors;
|
|
@@ -2,12 +2,12 @@ import AddEntryCommand from './commands/AddEntryCommand.mjs';
|
|
|
2
2
|
import AddSyncDeviceCommand from './commands/AddSyncDeviceCommand.mjs';
|
|
3
3
|
import DeleteEntryCommand from './commands/DeleteEntryCommand.mjs';
|
|
4
4
|
import UpdateEntryCommand from './commands/UpdateEntryCommand.mjs';
|
|
5
|
-
import
|
|
5
|
+
import ChangeDeviceInfoCommand from './commands/ChangeDeviceInfoCommand.mjs';
|
|
6
6
|
const commandConstructors = {
|
|
7
7
|
AddEntry: AddEntryCommand,
|
|
8
8
|
DeleteEntry: DeleteEntryCommand,
|
|
9
9
|
UpdateEntry: UpdateEntryCommand,
|
|
10
10
|
AddSyncDevice: AddSyncDeviceCommand,
|
|
11
|
-
|
|
11
|
+
ChangeDeviceInfo: ChangeDeviceInfoCommand,
|
|
12
12
|
};
|
|
13
13
|
export default commandConstructors;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type TwoFaLibMediator from '../../TwoFaLibMediator.mjs';
|
|
2
2
|
import Command from '../BaseCommand.mjs';
|
|
3
|
-
import type { DeviceId } from '../../interfaces/SyncTypes.mjs';
|
|
3
|
+
import type { DeviceId, DeviceInfo } from '../../interfaces/SyncTypes.mjs';
|
|
4
4
|
import type { PublicKey } from '../../interfaces/CryptoLib.mjs';
|
|
5
5
|
export interface AddSyncDeviceData {
|
|
6
6
|
deviceId: DeviceId;
|
|
7
7
|
publicKey: PublicKey;
|
|
8
|
+
deviceInfo: DeviceInfo;
|
|
8
9
|
}
|
|
9
10
|
/**
|
|
10
11
|
* Represents a command that when executed add an entry to the vault.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type TwoFaLibMediator from '../../TwoFaLibMediator.mjs';
|
|
2
|
+
import Command from '../BaseCommand.mjs';
|
|
3
|
+
import type { DeviceFriendlyName, DeviceId, DeviceType } from '../../interfaces/SyncTypes.mjs';
|
|
4
|
+
export interface ChangeDeviceInfoData {
|
|
5
|
+
deviceId: DeviceId;
|
|
6
|
+
newDeviceInfo: {
|
|
7
|
+
deviceFriendlyName?: DeviceFriendlyName;
|
|
8
|
+
deviceType: DeviceType;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Represents a command that when executed changes the device info of a sync device
|
|
13
|
+
*/
|
|
14
|
+
declare class ChangeDeviceInfoCommand extends Command<ChangeDeviceInfoData> {
|
|
15
|
+
/**
|
|
16
|
+
* Creates a new ChangeDeviceMetaCommand instance.
|
|
17
|
+
* @inheritdoc
|
|
18
|
+
* @param data - The id of the device to change and the new meta info
|
|
19
|
+
*/
|
|
20
|
+
constructor(data: ChangeDeviceInfoData, id?: string, timestamp?: number, version?: string, fromRemote?: boolean);
|
|
21
|
+
/**
|
|
22
|
+
* Executes the command to change the device info
|
|
23
|
+
* @inheritdoc
|
|
24
|
+
* @throws {InvalidCommandError} If the referenced device cannot be found
|
|
25
|
+
*/
|
|
26
|
+
execute(mediator: TwoFaLibMediator): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* @inheritdoc
|
|
29
|
+
*/
|
|
30
|
+
createUndoCommand(): Command;
|
|
31
|
+
/**
|
|
32
|
+
* Validates the command data.
|
|
33
|
+
* @inheritdoc
|
|
34
|
+
*/
|
|
35
|
+
validate(mediator: TwoFaLibMediator): boolean;
|
|
36
|
+
}
|
|
37
|
+
export default ChangeDeviceInfoCommand;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { InvalidCommandError, TwoFALibError } from '../../TwoFALibError.mjs';
|
|
2
|
+
import Command from '../BaseCommand.mjs';
|
|
3
|
+
/**
|
|
4
|
+
* Represents a command that when executed changes the device info of a sync device
|
|
5
|
+
*/
|
|
6
|
+
class ChangeDeviceInfoCommand extends Command {
|
|
7
|
+
/**
|
|
8
|
+
* Creates a new ChangeDeviceMetaCommand instance.
|
|
9
|
+
* @inheritdoc
|
|
10
|
+
* @param data - The id of the device to change and the new meta info
|
|
11
|
+
*/
|
|
12
|
+
constructor(data, id, timestamp, version, fromRemote = false) {
|
|
13
|
+
super('ChangeDeviceInfo', data, id, timestamp, version, fromRemote);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Executes the command to change the device info
|
|
17
|
+
* @inheritdoc
|
|
18
|
+
* @throws {InvalidCommandError} If the referenced device cannot be found
|
|
19
|
+
*/
|
|
20
|
+
async execute(mediator) {
|
|
21
|
+
if (!this.validate(mediator)) {
|
|
22
|
+
throw new InvalidCommandError('Failed to validate ChangeDeviceInfo command');
|
|
23
|
+
}
|
|
24
|
+
const lib = mediator.getComponent('lib');
|
|
25
|
+
if (this.data.deviceId === lib.meta.deviceId) {
|
|
26
|
+
// we're changing our own friendly name
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
28
|
+
lib['favaMeta'].deviceFriendlyName =
|
|
29
|
+
this.data.newDeviceInfo.deviceFriendlyName;
|
|
30
|
+
}
|
|
31
|
+
const syncManager = mediator.getComponent('syncManager');
|
|
32
|
+
if (syncManager) {
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
34
|
+
const device = syncManager['syncDevices'].find((d) => d.deviceId === this.data.deviceId);
|
|
35
|
+
if (!device) {
|
|
36
|
+
throw new InvalidCommandError('Trying to change info of device that is not found');
|
|
37
|
+
}
|
|
38
|
+
device.deviceInfo = this.data.newDeviceInfo;
|
|
39
|
+
}
|
|
40
|
+
await mediator.getComponent('persistentStorageManager').save();
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* @inheritdoc
|
|
44
|
+
*/
|
|
45
|
+
createUndoCommand() {
|
|
46
|
+
throw new TwoFALibError('Not implemented yet');
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Validates the command data.
|
|
50
|
+
* @inheritdoc
|
|
51
|
+
*/
|
|
52
|
+
validate(mediator) {
|
|
53
|
+
const lib = mediator.getComponent('lib');
|
|
54
|
+
if (this.fromRemote) {
|
|
55
|
+
// we can only validate this command locally
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
if (this.data.deviceId !== lib.meta.deviceId) {
|
|
59
|
+
// device ids are not identical
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
if (this.data.newDeviceInfo.deviceType !== lib.meta.deviceType) {
|
|
63
|
+
// Changing device type
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
const deviceFriendlyName = this.data.newDeviceInfo.deviceFriendlyName;
|
|
67
|
+
if (deviceFriendlyName !== undefined) {
|
|
68
|
+
if (deviceFriendlyName.length > 256) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
if (deviceFriendlyName.length < 1) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
export default ChangeDeviceInfoCommand;
|
package/build/TwoFaLib.d.mts
CHANGED
|
@@ -18,7 +18,7 @@ declare class TwoFaLib extends TypedEventTarget<TwoFaLibEventMapEvents> {
|
|
|
18
18
|
static readonly version = "0.0.1";
|
|
19
19
|
private readonly favaMeta;
|
|
20
20
|
readonly deviceType: DeviceType;
|
|
21
|
-
deviceFriendlyName
|
|
21
|
+
deviceFriendlyName?: DeviceFriendlyName;
|
|
22
22
|
private mediator;
|
|
23
23
|
private readonly publicKey;
|
|
24
24
|
private readonly privateKey;
|
|
@@ -28,7 +28,7 @@ declare class TwoFaLib extends TypedEventTarget<TwoFaLibEventMapEvents> {
|
|
|
28
28
|
*/
|
|
29
29
|
get meta(): {
|
|
30
30
|
deviceId: import("./interfaces/SyncTypes.mjs").DeviceId;
|
|
31
|
-
deviceFriendlyName: DeviceFriendlyName;
|
|
31
|
+
deviceFriendlyName: string | DeviceFriendlyName;
|
|
32
32
|
deviceType: DeviceType;
|
|
33
33
|
};
|
|
34
34
|
/**
|
|
@@ -42,7 +42,7 @@ declare class TwoFaLib extends TypedEventTarget<TwoFaLibEventMapEvents> {
|
|
|
42
42
|
* @param encryptedSymmetricKey - The encrypted symmetric key
|
|
43
43
|
* @param salt - The salt used for key derivation.
|
|
44
44
|
* @param publicKey - The public key of the device.
|
|
45
|
-
* @param favaMeta - Meta info containing at least a unique identifier for this device.
|
|
45
|
+
* @param favaMeta - Meta info about this device containing at least a unique identifier for this device.
|
|
46
46
|
* @param vault - The vault data (entries)
|
|
47
47
|
* @param saveFunction - The function to save the data.
|
|
48
48
|
* @param syncState - The state of the sync, includes the serverUrl
|
|
@@ -81,6 +81,11 @@ declare class TwoFaLib extends TypedEventTarget<TwoFaLibEventMapEvents> {
|
|
|
81
81
|
* @param force - Force setting the sync server url, even if no connection can be made
|
|
82
82
|
*/
|
|
83
83
|
setSyncServerUrl(serverUrl: string, force?: boolean): Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* Set a friendly name for this vault (used in syncing)
|
|
86
|
+
* @param deviceFriendlyName Human readable name for the device
|
|
87
|
+
*/
|
|
88
|
+
setDeviceFriendlyName(deviceFriendlyName: DeviceFriendlyName): Promise<void>;
|
|
84
89
|
/**
|
|
85
90
|
* Dispatches a library event.
|
|
86
91
|
* @param eventType - The type of the event to dispatch, uses the TwoFaLibEvent enum.
|
package/build/TwoFaLib.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { TypedEventTarget } from 'typescript-event-target';
|
|
2
2
|
import TwoFaLibMediator from './TwoFaLibMediator.mjs';
|
|
3
3
|
import { TwoFaLibEvent } from './TwoFaLibEvent.mjs';
|
|
4
|
-
import { InitializationError, SyncError } from './TwoFALibError.mjs';
|
|
4
|
+
import { InitializationError, SyncError, TwoFALibError, } from './TwoFALibError.mjs';
|
|
5
5
|
import SyncManager, { ConnectionStatus } from './subclasses/SyncManager.mjs';
|
|
6
6
|
import LibraryLoader from './subclasses/LibraryLoader.mjs';
|
|
7
7
|
import ExportImportManager from './subclasses/ExportImportManager.mjs';
|
|
@@ -10,6 +10,7 @@ import VaultDataManager from './subclasses/VaultDataManager.mjs';
|
|
|
10
10
|
import VaultOperationsManager from './subclasses/VaultOperationsManager.mjs';
|
|
11
11
|
import CommandManager from './subclasses/CommandManager.mjs';
|
|
12
12
|
import StorageOperationsManager from './subclasses/StorageOperationsManager.mjs';
|
|
13
|
+
import ChangeDeviceInfoCommand from './Command/commands/ChangeDeviceInfoCommand.mjs';
|
|
13
14
|
/**
|
|
14
15
|
* The Two-Factor Library, this is the main entry point.
|
|
15
16
|
*/
|
|
@@ -37,7 +38,7 @@ class TwoFaLib extends TypedEventTarget {
|
|
|
37
38
|
* @param encryptedSymmetricKey - The encrypted symmetric key
|
|
38
39
|
* @param salt - The salt used for key derivation.
|
|
39
40
|
* @param publicKey - The public key of the device.
|
|
40
|
-
* @param favaMeta - Meta info containing at least a unique identifier for this device.
|
|
41
|
+
* @param favaMeta - Meta info about this device containing at least a unique identifier for this device.
|
|
41
42
|
* @param vault - The vault data (entries)
|
|
42
43
|
* @param saveFunction - The function to save the data.
|
|
43
44
|
* @param syncState - The state of the sync, includes the serverUrl
|
|
@@ -47,7 +48,6 @@ class TwoFaLib extends TypedEventTarget {
|
|
|
47
48
|
*/
|
|
48
49
|
constructor(deviceType, cryptoLib, passphraseExtraDict, privateKey, symmetricKey, encryptedPrivateKey, encryptedSymmetricKey, salt, publicKey, favaMeta, vault, saveFunction, syncState) {
|
|
49
50
|
super();
|
|
50
|
-
this.deviceFriendlyName = '';
|
|
51
51
|
if (!deviceType) {
|
|
52
52
|
throw new InitializationError('Device type is required');
|
|
53
53
|
}
|
|
@@ -85,13 +85,14 @@ class TwoFaLib extends TypedEventTarget {
|
|
|
85
85
|
],
|
|
86
86
|
['dispatchLibEvent', this.dispatchLibEvent.bind(this)],
|
|
87
87
|
['log', this.log.bind(this)],
|
|
88
|
+
['lib', this],
|
|
88
89
|
]);
|
|
89
90
|
if (vault) {
|
|
90
91
|
this.mediator.getComponent('vaultDataManager').replaceVault(vault);
|
|
91
92
|
}
|
|
92
93
|
if (syncState?.serverUrl) {
|
|
93
94
|
// Initiate the syncManager
|
|
94
|
-
this.mediator.registerComponent('syncManager', new SyncManager(this.mediator, this.publicKey, this.privateKey, this.
|
|
95
|
+
this.mediator.registerComponent('syncManager', new SyncManager(this.mediator, this.publicKey, this.privateKey, this.favaMeta, syncState, this.deviceType));
|
|
95
96
|
}
|
|
96
97
|
else {
|
|
97
98
|
// If no syncmanager we're ready now, otherwise the syncmanager is responsible for emitting the ready event
|
|
@@ -161,7 +162,7 @@ class TwoFaLib extends TypedEventTarget {
|
|
|
161
162
|
devices: [],
|
|
162
163
|
commandSendQueue: [],
|
|
163
164
|
};
|
|
164
|
-
const newSyncManager = new SyncManager(this.mediator, this.publicKey, this.privateKey, this.
|
|
165
|
+
const newSyncManager = new SyncManager(this.mediator, this.publicKey, this.privateKey, this.favaMeta, newSyncState, this.deviceType);
|
|
165
166
|
const success = await new Promise((resolve) => {
|
|
166
167
|
this.addEventListener(TwoFaLibEvent.ConnectionToSyncServerStatusChanged, (event) => {
|
|
167
168
|
if (event.detail.newStatus === ConnectionStatus.CONNECTED) {
|
|
@@ -192,6 +193,21 @@ class TwoFaLib extends TypedEventTarget {
|
|
|
192
193
|
// save
|
|
193
194
|
await this.persistentStorageManager.save();
|
|
194
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* Set a friendly name for this vault (used in syncing)
|
|
198
|
+
* @param deviceFriendlyName Human readable name for the device
|
|
199
|
+
*/
|
|
200
|
+
async setDeviceFriendlyName(deviceFriendlyName) {
|
|
201
|
+
const data = {
|
|
202
|
+
deviceId: this.favaMeta.deviceId,
|
|
203
|
+
newDeviceInfo: { deviceType: this.deviceType, deviceFriendlyName },
|
|
204
|
+
};
|
|
205
|
+
const command = ChangeDeviceInfoCommand.create(data);
|
|
206
|
+
if (!command.validate(this.mediator)) {
|
|
207
|
+
throw new TwoFALibError('Device friendly name has invalid length, max 256 characters');
|
|
208
|
+
}
|
|
209
|
+
await this.mediator.getComponent('commandManager').execute(command);
|
|
210
|
+
}
|
|
195
211
|
/**
|
|
196
212
|
* Dispatches a library event.
|
|
197
213
|
* @param eventType - The type of the event to dispatch, uses the TwoFaLibEvent enum.
|
|
@@ -2,7 +2,7 @@ import type { AddEntryData } from '../Command/commands/AddEntryCommand.mjs';
|
|
|
2
2
|
import type { DeleteEntryData } from '../Command/commands/DeleteEntryCommand.mjs';
|
|
3
3
|
import type { UpdateEntryData } from '../Command/commands/UpdateEntryCommand.mjs';
|
|
4
4
|
import type { AddSyncDeviceData } from '../Command/commands/AddSyncDeviceCommand.mjs';
|
|
5
|
-
import type {
|
|
5
|
+
import type { ChangeDeviceInfoData } from '../Command/commands/ChangeDeviceInfoCommand.mjs';
|
|
6
6
|
export type SyncCommand = ({
|
|
7
7
|
type: 'AddEntry';
|
|
8
8
|
data: AddEntryData;
|
|
@@ -16,9 +16,9 @@ export type SyncCommand = ({
|
|
|
16
16
|
type: 'AddSyncDevice';
|
|
17
17
|
data: AddSyncDeviceData;
|
|
18
18
|
} | {
|
|
19
|
-
type: '
|
|
20
|
-
data:
|
|
19
|
+
type: 'ChangeDeviceInfo';
|
|
20
|
+
data: ChangeDeviceInfoData;
|
|
21
21
|
}) & {
|
|
22
22
|
id: string;
|
|
23
23
|
};
|
|
24
|
-
export type CommandData = AddEntryData | DeleteEntryData | UpdateEntryData | AddSyncDeviceData |
|
|
24
|
+
export type CommandData = AddEntryData | DeleteEntryData | UpdateEntryData | AddSyncDeviceData | ChangeDeviceInfoData;
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import type { Tagged } from 'type-fest';
|
|
2
2
|
import type { JPakeThreePass, Round1Result } from 'jpake-ts';
|
|
3
|
-
import { PublicKey, SyncKey } from './CryptoLib.mjs';
|
|
3
|
+
import type { PublicKey, SyncKey } from './CryptoLib.mjs';
|
|
4
|
+
import type { Vault, VaultSyncState } from './Vault.mjs';
|
|
4
5
|
export type DeviceId = Tagged<string, 'DeviceId'>;
|
|
5
6
|
export type DeviceType = Tagged<string, 'DeviceType'>;
|
|
6
7
|
export type DeviceFriendlyName = Tagged<string, 'DeviceFriendlyName'>;
|
|
8
|
+
export interface DeviceInfo {
|
|
9
|
+
deviceType: DeviceType;
|
|
10
|
+
deviceFriendlyName?: DeviceFriendlyName;
|
|
11
|
+
}
|
|
7
12
|
export interface SyncDevice {
|
|
8
13
|
deviceId: DeviceId;
|
|
9
14
|
publicKey: PublicKey;
|
|
10
|
-
|
|
11
|
-
deviceType: DeviceType;
|
|
12
|
-
deviceFriendlyName: DeviceFriendlyName;
|
|
13
|
-
};
|
|
15
|
+
deviceInfo?: DeviceInfo;
|
|
14
16
|
}
|
|
15
|
-
export type PublicSyncDevice = Omit<SyncDevice, 'publicKey'>;
|
|
17
|
+
export type PublicSyncDevice = Omit<SyncDevice, 'publicKey' | 'deviceInfo'> & Partial<SyncDevice['deviceInfo']>;
|
|
16
18
|
export interface BaseAddDeviceFlow {
|
|
17
19
|
jpak: JPakeThreePass;
|
|
18
20
|
addDevicePassword: Uint8Array;
|
|
@@ -45,3 +47,10 @@ export interface InitiateAddDeviceFlowResult {
|
|
|
45
47
|
timestamp: number;
|
|
46
48
|
pass1Result: Record<keyof Round1Result, string>;
|
|
47
49
|
}
|
|
50
|
+
export interface VaultStateSend {
|
|
51
|
+
deviceId: DeviceId;
|
|
52
|
+
forDeviceId: DeviceId;
|
|
53
|
+
deviceFriendlyName?: DeviceFriendlyName;
|
|
54
|
+
vault: Vault;
|
|
55
|
+
sync: VaultSyncState;
|
|
56
|
+
}
|
package/build/main.d.mts
CHANGED
|
@@ -3,11 +3,11 @@ import type Entry from './interfaces/Entry.mjs';
|
|
|
3
3
|
import type { EntryId, NewEntry, EntryMeta, EntryType, TotpPayload, Token, EntryMetaWithToken } from './interfaces/Entry.mjs';
|
|
4
4
|
import type CryptoLib from './interfaces/CryptoLib.mjs';
|
|
5
5
|
import type { Encrypted, EncryptedPrivateKey, EncryptedSymmetricKey, EncryptedPublicKey, PrivateKey, SymmetricKey, PublicKey, Passphrase, Salt } from './interfaces/CryptoLib.mjs';
|
|
6
|
-
import type { PublicSyncDevice, DeviceId, DeviceType, DeviceFriendlyName } from './interfaces/SyncTypes.mjs';
|
|
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
9
|
import { TwoFALibError, InitializationError, AuthenticationError, EntryNotFoundError, TokenGenerationError } from './TwoFALibError.mjs';
|
|
10
10
|
import { TwoFaLibEvent } from './TwoFaLibEvent.mjs';
|
|
11
11
|
import { getTwoFaLibVaultCreationUtils } from './utils/creationUtils.mjs';
|
|
12
12
|
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, PublicSyncDevice, SaveFunction, };
|
|
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, };
|
|
@@ -3,7 +3,8 @@ import { EncryptedVaultStateString, LockedRepresentationString } from '../interf
|
|
|
3
3
|
import type TwoFaLibMediator from '../TwoFaLibMediator.mjs';
|
|
4
4
|
import type { FavaMeta } from '../interfaces/FavaMeta.mjs';
|
|
5
5
|
import type { PassphraseExtraDict } from '../interfaces/PassphraseExtraDict.js';
|
|
6
|
-
import { SaveFunction } from '../interfaces/SaveFunction.mjs';
|
|
6
|
+
import type { SaveFunction } from '../interfaces/SaveFunction.mjs';
|
|
7
|
+
import type { DeviceId } from '../interfaces/SyncTypes.mjs';
|
|
7
8
|
/**
|
|
8
9
|
* Manages all storage of data that should be persistent.
|
|
9
10
|
*/
|
|
@@ -39,9 +40,10 @@ declare class PersistentStorageManager {
|
|
|
39
40
|
* Retrieves an encrypted representation of the library's current state.
|
|
40
41
|
* This can be used for secure storage or transmission of the library's data.
|
|
41
42
|
* @param key - The key to decrypt the locked representation with. If not provided the library's current symmetric key will be used.
|
|
43
|
+
* @param forDeviceId - If the vault is meant for a specific deviceId
|
|
42
44
|
* @returns A promise that resolves with a string representation of the locked state.
|
|
43
45
|
*/
|
|
44
|
-
getEncryptedVaultState(key?: SymmetricKey): Promise<EncryptedVaultStateString>;
|
|
46
|
+
getEncryptedVaultState(key?: SymmetricKey, forDeviceId?: DeviceId): Promise<EncryptedVaultStateString>;
|
|
45
47
|
/**
|
|
46
48
|
* Creates a partially encrypted representation of all data, except for
|
|
47
49
|
* the passphrase, that is needed to load the library. This can be used
|
|
@@ -46,13 +46,15 @@ class PersistentStorageManager {
|
|
|
46
46
|
* Retrieves an encrypted representation of the library's current state.
|
|
47
47
|
* This can be used for secure storage or transmission of the library's data.
|
|
48
48
|
* @param key - The key to decrypt the locked representation with. If not provided the library's current symmetric key will be used.
|
|
49
|
+
* @param forDeviceId - If the vault is meant for a specific deviceId
|
|
49
50
|
* @returns A promise that resolves with a string representation of the locked state.
|
|
50
51
|
*/
|
|
51
|
-
async getEncryptedVaultState(key) {
|
|
52
|
+
async getEncryptedVaultState(key, forDeviceId) {
|
|
52
53
|
const vault = this.vaultDataManager.getAllEntries();
|
|
53
54
|
const vaultState = {
|
|
54
55
|
vault,
|
|
55
56
|
deviceId: this.favaMeta.deviceId,
|
|
57
|
+
forDeviceId,
|
|
56
58
|
deviceFriendlyName: this.favaMeta.deviceFriendlyName,
|
|
57
59
|
sync: {
|
|
58
60
|
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SyncDevice, PublicSyncDevice,
|
|
1
|
+
import { SyncDevice, PublicSyncDevice, DeviceType } from '../interfaces/SyncTypes.mjs';
|
|
2
2
|
import type { PrivateKey, PublicKey } from '../interfaces/CryptoLib.mjs';
|
|
3
3
|
import type Command from '../Command/BaseCommand.mjs';
|
|
4
4
|
import type TwoFaLibMediator from '../TwoFaLibMediator.mjs';
|
|
@@ -32,7 +32,10 @@ declare class SyncManager {
|
|
|
32
32
|
private terminateTimeout?;
|
|
33
33
|
private connectionFailedTimeout?;
|
|
34
34
|
private shouldReconnect;
|
|
35
|
+
private requestedResilver;
|
|
36
|
+
private requestedResilverTimeout?;
|
|
35
37
|
private get deviceId();
|
|
38
|
+
private get deviceInfo();
|
|
36
39
|
/**
|
|
37
40
|
* Public getter for the command send queue.
|
|
38
41
|
* @returns The command send queue.
|
|
@@ -136,8 +139,8 @@ declare class SyncManager {
|
|
|
136
139
|
respondToAddDeviceFlow(initiatorData: string | Uint8Array | File, initiatorDataType: 'text' | 'qr'): Promise<void>;
|
|
137
140
|
private finishAddDeviceFlowKeyExchangeInitiator;
|
|
138
141
|
private finishAddDeviceFlowKeyExchangeResponder;
|
|
139
|
-
private
|
|
140
|
-
private
|
|
142
|
+
private sendFullVaultDataAndSetDeviceInfo;
|
|
143
|
+
private importInitialVault;
|
|
141
144
|
private importVaultState;
|
|
142
145
|
/**
|
|
143
146
|
* Cancels the active add sync device flow.
|
|
@@ -169,19 +172,14 @@ declare class SyncManager {
|
|
|
169
172
|
private resilver;
|
|
170
173
|
/**
|
|
171
174
|
* Add a sync device
|
|
172
|
-
* @param
|
|
175
|
+
* @param device - The device to add
|
|
173
176
|
* @param saveAfter - Whether to save the new vault after adding it (set to false when adding multiple devices)
|
|
174
177
|
*/
|
|
175
|
-
addSyncDevice(
|
|
178
|
+
addSyncDevice(device: SyncDevice, saveAfter?: boolean): Promise<void>;
|
|
176
179
|
/**
|
|
177
180
|
* Requests a resilver of the vault
|
|
178
181
|
*/
|
|
179
|
-
requestResilver(): void
|
|
180
|
-
/**
|
|
181
|
-
* Change the meta of the current device, allows setting a friendly name
|
|
182
|
-
* @param deviceFriendlyName Human readable name for the device
|
|
183
|
-
*/
|
|
184
|
-
setDeviceFriendlyName(deviceFriendlyName: DeviceFriendlyName): Promise<void>;
|
|
182
|
+
requestResilver(): Promise<void>;
|
|
185
183
|
/**
|
|
186
184
|
* Function to call when the server connection should be closed
|
|
187
185
|
*/
|
|
@@ -4,7 +4,6 @@ import { TwoFaLibEvent } from '../TwoFaLibEvent.mjs';
|
|
|
4
4
|
import { decodeInitiatorData, jsonToUint8Array } from '../utils/syncUtils.mjs';
|
|
5
5
|
import { InitializationError, SyncAddDeviceFlowConflictError, SyncError, SyncInWrongStateError, SyncNoServerConnectionError, TwoFALibError, } from '../TwoFALibError.mjs';
|
|
6
6
|
import AddSyncDeviceCommand from '../Command/commands/AddSyncDeviceCommand.mjs';
|
|
7
|
-
import ChangeSyncDeviceMetaCommand from '../Command/commands/ChangeSyncDeviceMetaCommand.mjs';
|
|
8
7
|
const IN_TESTING = process.env.NODE_ENV === 'test';
|
|
9
8
|
const IN_DEV = process.env.NODE_ENV === 'development';
|
|
10
9
|
export var ConnectionStatus;
|
|
@@ -26,6 +25,12 @@ class SyncManager {
|
|
|
26
25
|
get deviceId() {
|
|
27
26
|
return this.favaMeta.deviceId;
|
|
28
27
|
}
|
|
28
|
+
get deviceInfo() {
|
|
29
|
+
return {
|
|
30
|
+
deviceType: this.deviceType,
|
|
31
|
+
deviceFriendlyName: this.favaMeta.deviceFriendlyName,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
29
34
|
/**
|
|
30
35
|
* Public getter for the command send queue.
|
|
31
36
|
* @returns The command send queue.
|
|
@@ -42,7 +47,7 @@ class SyncManager {
|
|
|
42
47
|
.filter((d) => d.deviceId !== this.deviceId)
|
|
43
48
|
.map((d) => ({
|
|
44
49
|
deviceId: d.deviceId,
|
|
45
|
-
|
|
50
|
+
...d.deviceInfo,
|
|
46
51
|
}));
|
|
47
52
|
}
|
|
48
53
|
/**
|
|
@@ -65,6 +70,7 @@ class SyncManager {
|
|
|
65
70
|
this.readyEventEmitted = false;
|
|
66
71
|
this.commandSendQueue = [];
|
|
67
72
|
this.shouldReconnect = true;
|
|
73
|
+
this.requestedResilver = false;
|
|
68
74
|
const { serverUrl, devices, commandSendQueue } = syncState;
|
|
69
75
|
if (!serverUrl.startsWith('wss://')) {
|
|
70
76
|
if (!serverUrl.startsWith('ws://') && !(IN_DEV || IN_TESTING)) {
|
|
@@ -79,6 +85,7 @@ class SyncManager {
|
|
|
79
85
|
void this.addSyncDevice({
|
|
80
86
|
deviceId: this.favaMeta.deviceId,
|
|
81
87
|
publicKey: this.publicKey,
|
|
88
|
+
deviceInfo: this.deviceInfo,
|
|
82
89
|
}, false);
|
|
83
90
|
// if not yet connected after 2 tries, emit ready event so we can continue
|
|
84
91
|
this.connectionFailedTimeout = setTimeout(() => {
|
|
@@ -216,21 +223,27 @@ class SyncManager {
|
|
|
216
223
|
void this.finishAddDeviceFlowKeyExchangeResponder(pass3Result);
|
|
217
224
|
break;
|
|
218
225
|
}
|
|
219
|
-
case '
|
|
226
|
+
case 'publicKeyAndDeviceInfo': {
|
|
220
227
|
const { data } = message;
|
|
221
|
-
const { responderEncryptedPublicKey } = data;
|
|
222
|
-
void this.
|
|
228
|
+
const { responderEncryptedPublicKey, responderEncryptedDeviceInfo } = data;
|
|
229
|
+
void this.sendFullVaultDataAndSetDeviceInfo(responderEncryptedPublicKey, responderEncryptedDeviceInfo);
|
|
223
230
|
break;
|
|
224
231
|
}
|
|
225
232
|
case 'initialVault': {
|
|
226
233
|
const { data } = message;
|
|
227
234
|
const { encryptedVaultData } = data;
|
|
228
|
-
void this.
|
|
235
|
+
void this.importInitialVault(encryptedVaultData);
|
|
229
236
|
break;
|
|
230
237
|
}
|
|
231
238
|
case 'vault': {
|
|
239
|
+
if (!this.requestedResilver) {
|
|
240
|
+
throw new SyncError('Got vault data while no resilver was requested, probably replay attack!');
|
|
241
|
+
}
|
|
232
242
|
const { data } = message;
|
|
233
|
-
const { encryptedVaultData, encryptedSymmetricKey, fromDeviceId } = data;
|
|
243
|
+
const { encryptedVaultData, encryptedSymmetricKey, fromDeviceId, forDeviceId, } = data;
|
|
244
|
+
if (forDeviceId !== this.deviceId) {
|
|
245
|
+
throw new SyncError('Got vault data for the wrong device!');
|
|
246
|
+
}
|
|
234
247
|
void this.cryptoLib
|
|
235
248
|
.decrypt(this.privateKey, encryptedSymmetricKey)
|
|
236
249
|
.then((symmetricKey) => this.importVaultState(encryptedVaultData, symmetricKey, fromDeviceId));
|
|
@@ -422,14 +435,16 @@ class SyncManager {
|
|
|
422
435
|
syncKey,
|
|
423
436
|
};
|
|
424
437
|
const responderEncryptedPublicKey = await this.cryptoLib.encryptSymmetric(syncKey, this.publicKey);
|
|
438
|
+
const responderEncryptedDeviceInfo = await this.cryptoLib.encryptSymmetric(syncKey, JSON.stringify(this.deviceInfo));
|
|
425
439
|
// send our public key
|
|
426
|
-
this.sendToServer('
|
|
440
|
+
this.sendToServer('publicKeyAndDeviceInfo', {
|
|
427
441
|
nonce: await this.getNonce(),
|
|
428
442
|
responderEncryptedPublicKey,
|
|
443
|
+
responderEncryptedDeviceInfo,
|
|
429
444
|
initiatorDeviceId: this.activeAddDeviceFlow.initiatorDeviceId,
|
|
430
445
|
});
|
|
431
446
|
}
|
|
432
|
-
async
|
|
447
|
+
async sendFullVaultDataAndSetDeviceInfo(responderEncryptedPublicKey, responderEncryptedDeviceInfo) {
|
|
433
448
|
if (!this.ws || !this.webSocketConnected) {
|
|
434
449
|
throw new SyncNoServerConnectionError();
|
|
435
450
|
}
|
|
@@ -442,8 +457,10 @@ class SyncManager {
|
|
|
442
457
|
const syncKey = this.activeAddDeviceFlow.syncKey;
|
|
443
458
|
// Decrypt the received public key
|
|
444
459
|
const decryptedPublicKey = await this.cryptoLib.decryptSymmetric(syncKey, responderEncryptedPublicKey);
|
|
460
|
+
// decrypt the received device info
|
|
461
|
+
const responderDeviceInfo = JSON.parse(await this.cryptoLib.decryptSymmetric(syncKey, responderEncryptedDeviceInfo));
|
|
445
462
|
// get the vault data (encrypted with the sync key)
|
|
446
|
-
const encryptedVaultData = await this.persistentStorageManager.getEncryptedVaultState(syncKey);
|
|
463
|
+
const encryptedVaultData = await this.persistentStorageManager.getEncryptedVaultState(syncKey, this.activeAddDeviceFlow.responderDeviceId);
|
|
447
464
|
// Send the encrypted vault data to the server
|
|
448
465
|
this.sendToServer('initialVault', {
|
|
449
466
|
nonce: await this.getNonce(),
|
|
@@ -454,12 +471,13 @@ class SyncManager {
|
|
|
454
471
|
const command = AddSyncDeviceCommand.create({
|
|
455
472
|
deviceId: this.activeAddDeviceFlow.responderDeviceId,
|
|
456
473
|
publicKey: decryptedPublicKey,
|
|
474
|
+
deviceInfo: responderDeviceInfo,
|
|
457
475
|
});
|
|
458
476
|
await this.commandManager.execute(command);
|
|
459
477
|
// all done
|
|
460
478
|
this.activeAddDeviceFlow = undefined;
|
|
461
479
|
}
|
|
462
|
-
async
|
|
480
|
+
async importInitialVault(encryptedVaultState) {
|
|
463
481
|
if (this.activeAddDeviceFlow?.state !== 'responder:syncKeyCreated') {
|
|
464
482
|
throw new SyncInWrongStateError(`Expected responder:syncKeyCreated, got ${this.activeAddDeviceFlow?.state}`);
|
|
465
483
|
}
|
|
@@ -473,6 +491,9 @@ class SyncManager {
|
|
|
473
491
|
if (vaultState.deviceId !== expectedDeviceId) {
|
|
474
492
|
throw new SyncError(`DeviceId mismatch when importing, expected ${expectedDeviceId} got ${vaultState.deviceId}`);
|
|
475
493
|
}
|
|
494
|
+
if (vaultState.forDeviceId !== this.deviceId) {
|
|
495
|
+
throw new SyncError(`For deviceId mismatch when importing, expected ${this.deviceId} got ${vaultState.forDeviceId}`);
|
|
496
|
+
}
|
|
476
497
|
for (const device of vaultState.sync.devices) {
|
|
477
498
|
await this.addSyncDevice(device, false);
|
|
478
499
|
}
|
|
@@ -513,6 +534,7 @@ class SyncManager {
|
|
|
513
534
|
// skip ourselves
|
|
514
535
|
return;
|
|
515
536
|
}
|
|
537
|
+
// unique symmetricKey per command
|
|
516
538
|
const symmetricKey = await this.cryptoLib.createSymmetricKey();
|
|
517
539
|
const encryptedSymmetricKey = await this.cryptoLib.encrypt(device.publicKey, symmetricKey);
|
|
518
540
|
const encryptedCommand = await this.cryptoLib.encryptSymmetric(symmetricKey, JSON.stringify({
|
|
@@ -594,7 +616,7 @@ class SyncManager {
|
|
|
594
616
|
}
|
|
595
617
|
const symmetricKey = await this.cryptoLib.createSymmetricKey();
|
|
596
618
|
const encryptedSymmetricKey = await this.cryptoLib.encrypt(device.publicKey, symmetricKey);
|
|
597
|
-
const encryptedVaultData = await this.persistentStorageManager.getEncryptedVaultState(symmetricKey);
|
|
619
|
+
const encryptedVaultData = await this.persistentStorageManager.getEncryptedVaultState(symmetricKey, device.deviceId);
|
|
598
620
|
this.sendToServer('vault', {
|
|
599
621
|
forDeviceId: device.deviceId,
|
|
600
622
|
nonce: await this.getNonce(),
|
|
@@ -605,17 +627,17 @@ class SyncManager {
|
|
|
605
627
|
}
|
|
606
628
|
/**
|
|
607
629
|
* Add a sync device
|
|
608
|
-
* @param
|
|
630
|
+
* @param device - The device to add
|
|
609
631
|
* @param saveAfter - Whether to save the new vault after adding it (set to false when adding multiple devices)
|
|
610
632
|
*/
|
|
611
|
-
async addSyncDevice(
|
|
612
|
-
if (this.syncDevices.some((d) => d.deviceId ===
|
|
633
|
+
async addSyncDevice(device, saveAfter = true) {
|
|
634
|
+
if (this.syncDevices.some((d) => d.deviceId === device.deviceId)) {
|
|
613
635
|
// we already have this device
|
|
614
636
|
return;
|
|
615
637
|
}
|
|
616
|
-
this.log('info', `Adding syncdevice ${
|
|
638
|
+
this.log('info', `Adding syncdevice ${device.deviceId} to ${this.deviceId}`);
|
|
617
639
|
this.syncDevices.push({
|
|
618
|
-
...
|
|
640
|
+
...device,
|
|
619
641
|
});
|
|
620
642
|
if (saveAfter) {
|
|
621
643
|
await this.persistentStorageManager.save();
|
|
@@ -624,29 +646,18 @@ class SyncManager {
|
|
|
624
646
|
/**
|
|
625
647
|
* Requests a resilver of the vault
|
|
626
648
|
*/
|
|
627
|
-
requestResilver() {
|
|
649
|
+
async requestResilver() {
|
|
628
650
|
this.sendToServer('startResilver', {
|
|
629
651
|
deviceIds: this.syncDevices.map((d) => d.deviceId),
|
|
652
|
+
nonce: await this.getNonce(),
|
|
630
653
|
});
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
async setDeviceFriendlyName(deviceFriendlyName) {
|
|
637
|
-
if (deviceFriendlyName.length > 256) {
|
|
638
|
-
throw new TwoFALibError('Device friendly name is too long, max 256 characters');
|
|
654
|
+
// Set requestedResilver to true for 60 seconds, after this we no longer
|
|
655
|
+
// accept vault data
|
|
656
|
+
this.requestedResilver = true;
|
|
657
|
+
if (this.requestedResilverTimeout) {
|
|
658
|
+
clearTimeout(this.requestedResilverTimeout);
|
|
639
659
|
}
|
|
640
|
-
|
|
641
|
-
throw new TwoFALibError('Device friendly name is too short, min 1 character');
|
|
642
|
-
}
|
|
643
|
-
this.favaMeta.deviceFriendlyName = deviceFriendlyName;
|
|
644
|
-
const newMeta = {
|
|
645
|
-
deviceId: this.deviceId,
|
|
646
|
-
newMeta: { deviceType: this.deviceType, deviceFriendlyName },
|
|
647
|
-
};
|
|
648
|
-
const command = ChangeSyncDeviceMetaCommand.create(newMeta);
|
|
649
|
-
await this.commandManager.execute(command);
|
|
660
|
+
this.requestedResilverTimeout = setTimeout(() => (this.requestedResilver = false), 60 * 1000);
|
|
650
661
|
}
|
|
651
662
|
/**
|
|
652
663
|
* Function to call when the server connection should be closed
|
package/package.json
CHANGED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import type TwoFaLibMediator from '../../TwoFaLibMediator.mjs';
|
|
2
|
-
import Command from '../BaseCommand.mjs';
|
|
3
|
-
import type { DeviceFriendlyName, DeviceId, DeviceType } from '../../interfaces/SyncTypes.mjs';
|
|
4
|
-
export interface ChangeSyncDeviceMetaData {
|
|
5
|
-
deviceId: DeviceId;
|
|
6
|
-
newMeta: {
|
|
7
|
-
deviceFriendlyName: DeviceFriendlyName;
|
|
8
|
-
deviceType: DeviceType;
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Represents a command that when executed changes the meta info of a sync device
|
|
13
|
-
*/
|
|
14
|
-
declare class ChangeSyncDeviceMetaCommand extends Command<ChangeSyncDeviceMetaData> {
|
|
15
|
-
/**
|
|
16
|
-
* Creates a new ChangeSyncDeviceMetaCommand instance.
|
|
17
|
-
* @inheritdoc
|
|
18
|
-
* @param data - The id of the device to change and the new meta info
|
|
19
|
-
*/
|
|
20
|
-
constructor(data: ChangeSyncDeviceMetaData, id?: string, timestamp?: number, version?: string, fromRemote?: boolean);
|
|
21
|
-
/**
|
|
22
|
-
* Executes the command to change the sync device metadata
|
|
23
|
-
* @inheritdoc
|
|
24
|
-
* @throws {InvalidCommandError} If the referenced sync device cannot be found
|
|
25
|
-
*/
|
|
26
|
-
execute(mediator: TwoFaLibMediator): Promise<void>;
|
|
27
|
-
/**
|
|
28
|
-
* @inheritdoc
|
|
29
|
-
*/
|
|
30
|
-
createUndoCommand(): Command;
|
|
31
|
-
}
|
|
32
|
-
export default ChangeSyncDeviceMetaCommand;
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { InvalidCommandError, TwoFALibError } from '../../TwoFALibError.mjs';
|
|
2
|
-
import Command from '../BaseCommand.mjs';
|
|
3
|
-
/**
|
|
4
|
-
* Represents a command that when executed changes the meta info of a sync device
|
|
5
|
-
*/
|
|
6
|
-
class ChangeSyncDeviceMetaCommand extends Command {
|
|
7
|
-
/**
|
|
8
|
-
* Creates a new ChangeSyncDeviceMetaCommand instance.
|
|
9
|
-
* @inheritdoc
|
|
10
|
-
* @param data - The id of the device to change and the new meta info
|
|
11
|
-
*/
|
|
12
|
-
constructor(data, id, timestamp, version, fromRemote = false) {
|
|
13
|
-
super('ChangeSyncDeviceMeta', data, id, timestamp, version, fromRemote);
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Executes the command to change the sync device metadata
|
|
17
|
-
* @inheritdoc
|
|
18
|
-
* @throws {InvalidCommandError} If the referenced sync device cannot be found
|
|
19
|
-
*/
|
|
20
|
-
execute(mediator) {
|
|
21
|
-
const syncManager = mediator.getComponent('syncManager');
|
|
22
|
-
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
23
|
-
const device = syncManager['syncDevices'].find((d) => d.deviceId === this.data.deviceId);
|
|
24
|
-
if (!device) {
|
|
25
|
-
throw new InvalidCommandError('Trying to change meta of device that is not found');
|
|
26
|
-
}
|
|
27
|
-
device.meta = this.data.newMeta;
|
|
28
|
-
return Promise.resolve();
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* @inheritdoc
|
|
32
|
-
*/
|
|
33
|
-
createUndoCommand() {
|
|
34
|
-
throw new TwoFALibError('Not implemented yet');
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
export default ChangeSyncDeviceMetaCommand;
|