Add support for handling multiple accounts with native messaging (#1266)
This commit is contained in:
parent
a7c5f1ad45
commit
3c99920435
|
@ -1,5 +1,6 @@
|
||||||
import { Injectable } from "@angular/core";
|
import { Injectable } from "@angular/core";
|
||||||
import { ipcRenderer } from "electron";
|
import { ipcRenderer } from "electron";
|
||||||
|
import { firstValueFrom } from "rxjs";
|
||||||
import Swal from "sweetalert2";
|
import Swal from "sweetalert2";
|
||||||
|
|
||||||
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||||
|
@ -9,10 +10,10 @@ import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { StateService } from "jslib-common/abstractions/state.service";
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
|
|
||||||
|
|
||||||
import { Utils } from "jslib-common/misc/utils";
|
import { Utils } from "jslib-common/misc/utils";
|
||||||
|
|
||||||
|
import { EncString } from "jslib-common/models/domain/encString";
|
||||||
import { SymmetricCryptoKey } from "jslib-common/models/domain/symmetricCryptoKey";
|
import { SymmetricCryptoKey } from "jslib-common/models/domain/symmetricCryptoKey";
|
||||||
|
|
||||||
import { KeySuffixOptions } from "jslib-common/enums/keySuffixOptions";
|
import { KeySuffixOptions } from "jslib-common/enums/keySuffixOptions";
|
||||||
|
@ -20,6 +21,20 @@ import { KeySuffixOptions } from "jslib-common/enums/keySuffixOptions";
|
||||||
const MessageValidTimeout = 10 * 1000;
|
const MessageValidTimeout = 10 * 1000;
|
||||||
const EncryptionAlgorithm = "sha1";
|
const EncryptionAlgorithm = "sha1";
|
||||||
|
|
||||||
|
type Message = {
|
||||||
|
command: string;
|
||||||
|
|
||||||
|
userId?: string;
|
||||||
|
timestamp?: number;
|
||||||
|
|
||||||
|
publicKey?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type OuterMessage = {
|
||||||
|
message: Message | EncString;
|
||||||
|
appId: string;
|
||||||
|
};
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class NativeMessagingService {
|
export class NativeMessagingService {
|
||||||
private sharedSecrets = new Map<string, SymmetricCryptoKey>();
|
private sharedSecrets = new Map<string, SymmetricCryptoKey>();
|
||||||
|
@ -31,7 +46,6 @@ export class NativeMessagingService {
|
||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
private messagingService: MessagingService,
|
private messagingService: MessagingService,
|
||||||
private vaultTimeoutService: VaultTimeoutService,
|
|
||||||
private stateService: StateService
|
private stateService: StateService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
@ -41,16 +55,17 @@ export class NativeMessagingService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async messageHandler(msg: any) {
|
private async messageHandler(msg: OuterMessage) {
|
||||||
const appId = msg.appId;
|
const appId = msg.appId;
|
||||||
const rawMessage = msg.message;
|
const rawMessage = msg.message;
|
||||||
|
|
||||||
// Request to setup secure encryption
|
// Request to setup secure encryption
|
||||||
if (rawMessage.command === "setupEncryption") {
|
if ("command" in rawMessage && rawMessage.command === "setupEncryption") {
|
||||||
const remotePublicKey = Utils.fromB64ToArray(rawMessage.publicKey).buffer;
|
const remotePublicKey = Utils.fromB64ToArray(rawMessage.publicKey).buffer;
|
||||||
|
|
||||||
// Valudate the UserId to ensure we are logged into the same account.
|
// Valudate the UserId to ensure we are logged into the same account.
|
||||||
if (rawMessage.userId !== (await this.stateService.getUserId())) {
|
const userIds = Object.keys(this.stateService.accounts.getValue());
|
||||||
|
if (!userIds.includes(rawMessage.userId)) {
|
||||||
ipcRenderer.send("nativeMessagingReply", { command: "wrongUserId", appId: appId });
|
ipcRenderer.send("nativeMessagingReply", { command: "wrongUserId", appId: appId });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -87,8 +102,13 @@ export class NativeMessagingService {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const message = JSON.parse(
|
if (this.sharedSecrets.get(appId) == null) {
|
||||||
await this.cryptoService.decryptToUtf8(rawMessage, this.sharedSecrets.get(appId))
|
ipcRenderer.send("nativeMessagingReply", { command: "invalidateEncryption", appId: appId });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const message: Message = JSON.parse(
|
||||||
|
await this.cryptoService.decryptToUtf8(rawMessage as EncString, this.sharedSecrets.get(appId))
|
||||||
);
|
);
|
||||||
|
|
||||||
// Shared secret is invalidated, force re-authentication
|
// Shared secret is invalidated, force re-authentication
|
||||||
|
@ -108,7 +128,7 @@ export class NativeMessagingService {
|
||||||
return this.send({ command: "biometricUnlock", response: "not supported" }, appId);
|
return this.send({ command: "biometricUnlock", response: "not supported" }, appId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(await this.vaultTimeoutService.isBiometricLockSet())) {
|
if (!(await this.stateService.getBiometricUnlock({ userId: message.userId }))) {
|
||||||
this.send({ command: "biometricUnlock", response: "not enabled" }, appId);
|
this.send({ command: "biometricUnlock", response: "not enabled" }, appId);
|
||||||
|
|
||||||
return await Swal.fire({
|
return await Swal.fire({
|
||||||
|
@ -120,11 +140,16 @@ export class NativeMessagingService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const keyB64 = (await this.cryptoService.getKeyFromStorage(KeySuffixOptions.Biometric))
|
const key = await this.cryptoService.getKeyFromStorage(
|
||||||
.keyB64;
|
KeySuffixOptions.Biometric,
|
||||||
|
message.userId
|
||||||
|
);
|
||||||
|
|
||||||
if (keyB64 != null) {
|
if (key != null) {
|
||||||
this.send({ command: "biometricUnlock", response: "unlocked", keyB64: keyB64 }, appId);
|
this.send(
|
||||||
|
{ command: "biometricUnlock", response: "unlocked", keyB64: key.keyB64 },
|
||||||
|
appId
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
this.send({ command: "biometricUnlock", response: "canceled" }, appId);
|
this.send({ command: "biometricUnlock", response: "canceled" }, appId);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue