mirror of
https://github.com/bitwarden/desktop
synced 2026-01-06 02:23:24 +00:00
Apply Prettier (#1202)
This commit is contained in:
@@ -1,22 +1,67 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
import { I18nService as BaseI18nService } from 'jslib-common/services/i18n.service';
|
||||
import { I18nService as BaseI18nService } from "jslib-common/services/i18n.service";
|
||||
|
||||
export class I18nService extends BaseI18nService {
|
||||
constructor(systemLanguage: string, localesDirectory: string) {
|
||||
super(systemLanguage, localesDirectory, (formattedLocale: string) => {
|
||||
const filePath = path.join(__dirname, this.localesDirectory + '/' + formattedLocale + '/messages.json');
|
||||
const localesJson = fs.readFileSync(filePath, 'utf8');
|
||||
const locales = JSON.parse(localesJson.replace(/^\uFEFF/, '')); // strip the BOM
|
||||
return Promise.resolve(locales);
|
||||
});
|
||||
constructor(systemLanguage: string, localesDirectory: string) {
|
||||
super(systemLanguage, localesDirectory, (formattedLocale: string) => {
|
||||
const filePath = path.join(
|
||||
__dirname,
|
||||
this.localesDirectory + "/" + formattedLocale + "/messages.json"
|
||||
);
|
||||
const localesJson = fs.readFileSync(filePath, "utf8");
|
||||
const locales = JSON.parse(localesJson.replace(/^\uFEFF/, "")); // strip the BOM
|
||||
return Promise.resolve(locales);
|
||||
});
|
||||
|
||||
// Please leave 'en' where it is, as it's our fallback language in case no translation can be found
|
||||
this.supportedTranslationLocales = [
|
||||
'en', 'af', 'az', 'be', 'bg', 'bn', 'ca', 'cs', 'da', 'de', 'el', 'en-GB', 'en-IN', 'es', 'et', 'fa', 'fi', 'fr', 'he', 'hr', 'hu', 'id',
|
||||
'it', 'ja', 'kn', 'ko', 'lv', 'me', 'ml', 'nb', 'nl', 'pl', 'pt-BR', 'pt-PT', 'ro', 'ru', 'sk', 'sr', 'sv', 'th', 'tr', 'uk',
|
||||
'vi', 'zh-CN', 'zh-TW',
|
||||
];
|
||||
}
|
||||
// Please leave 'en' where it is, as it's our fallback language in case no translation can be found
|
||||
this.supportedTranslationLocales = [
|
||||
"en",
|
||||
"af",
|
||||
"az",
|
||||
"be",
|
||||
"bg",
|
||||
"bn",
|
||||
"ca",
|
||||
"cs",
|
||||
"da",
|
||||
"de",
|
||||
"el",
|
||||
"en-GB",
|
||||
"en-IN",
|
||||
"es",
|
||||
"et",
|
||||
"fa",
|
||||
"fi",
|
||||
"fr",
|
||||
"he",
|
||||
"hr",
|
||||
"hu",
|
||||
"id",
|
||||
"it",
|
||||
"ja",
|
||||
"kn",
|
||||
"ko",
|
||||
"lv",
|
||||
"me",
|
||||
"ml",
|
||||
"nb",
|
||||
"nl",
|
||||
"pl",
|
||||
"pt-BR",
|
||||
"pt-PT",
|
||||
"ro",
|
||||
"ru",
|
||||
"sk",
|
||||
"sr",
|
||||
"sv",
|
||||
"th",
|
||||
"tr",
|
||||
"uk",
|
||||
"vi",
|
||||
"zh-CN",
|
||||
"zh-TW",
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,28 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CanActivate } from '@angular/router';
|
||||
import { Injectable } from "@angular/core";
|
||||
import { CanActivate } from "@angular/router";
|
||||
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||
import { StateService } from "jslib-common/abstractions/state.service";
|
||||
|
||||
const maxAllowedAccounts = 5;
|
||||
|
||||
@Injectable()
|
||||
export class LoginGuardService implements CanActivate {
|
||||
protected homepage = 'vault';
|
||||
constructor(private stateService: StateService, private platformUtilsService: PlatformUtilsService,
|
||||
private i18nService: I18nService) { }
|
||||
protected homepage = "vault";
|
||||
constructor(
|
||||
private stateService: StateService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private i18nService: I18nService
|
||||
) {}
|
||||
|
||||
async canActivate() {
|
||||
const accounts = this.stateService.accounts.getValue();
|
||||
if (accounts != null && Object.keys(accounts).length >= maxAllowedAccounts) {
|
||||
this.platformUtilsService.showToast('error', null, this.i18nService.t('accountLimitReached'));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
async canActivate() {
|
||||
const accounts = this.stateService.accounts.getValue();
|
||||
if (accounts != null && Object.keys(accounts).length >= maxAllowedAccounts) {
|
||||
this.platformUtilsService.showToast("error", null, this.i18nService.t("accountLimitReached"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,137 +1,162 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import Swal from 'sweetalert2';
|
||||
import { Injectable } from "@angular/core";
|
||||
import { ipcRenderer } from "electron";
|
||||
import Swal from "sweetalert2";
|
||||
|
||||
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
|
||||
import { CryptoFunctionService } from 'jslib-common/abstractions/cryptoFunction.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
||||
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
||||
import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service';
|
||||
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||
import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service";
|
||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||
import { LogService } from "jslib-common/abstractions/log.service";
|
||||
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.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 { 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";
|
||||
|
||||
const MessageValidTimeout = 10 * 1000;
|
||||
const EncryptionAlgorithm = 'sha1';
|
||||
const EncryptionAlgorithm = "sha1";
|
||||
|
||||
@Injectable()
|
||||
export class NativeMessagingService {
|
||||
private sharedSecrets = new Map<string, SymmetricCryptoKey>();
|
||||
private sharedSecrets = new Map<string, SymmetricCryptoKey>();
|
||||
|
||||
constructor(private cryptoFunctionService: CryptoFunctionService, private cryptoService: CryptoService,
|
||||
private platformUtilService: PlatformUtilsService, private logService: LogService,
|
||||
private i18nService: I18nService, private messagingService: MessagingService,
|
||||
private vaultTimeoutService: VaultTimeoutService, private stateService: StateService) {
|
||||
ipcRenderer.on('nativeMessaging', async (_event: any, message: any) => {
|
||||
this.messageHandler(message);
|
||||
constructor(
|
||||
private cryptoFunctionService: CryptoFunctionService,
|
||||
private cryptoService: CryptoService,
|
||||
private platformUtilService: PlatformUtilsService,
|
||||
private logService: LogService,
|
||||
private i18nService: I18nService,
|
||||
private messagingService: MessagingService,
|
||||
private vaultTimeoutService: VaultTimeoutService,
|
||||
private stateService: StateService
|
||||
) {
|
||||
ipcRenderer.on("nativeMessaging", async (_event: any, message: any) => {
|
||||
this.messageHandler(message);
|
||||
});
|
||||
}
|
||||
|
||||
private async messageHandler(msg: any) {
|
||||
const appId = msg.appId;
|
||||
const rawMessage = msg.message;
|
||||
|
||||
// Request to setup secure encryption
|
||||
if (rawMessage.command === "setupEncryption") {
|
||||
const remotePublicKey = Utils.fromB64ToArray(rawMessage.publicKey).buffer;
|
||||
|
||||
// Valudate the UserId to ensure we are logged into the same account.
|
||||
if (rawMessage.userId !== (await this.stateService.getUserId())) {
|
||||
ipcRenderer.send("nativeMessagingReply", { command: "wrongUserId", appId: appId });
|
||||
return;
|
||||
}
|
||||
|
||||
if (await this.stateService.getEnableBrowserIntegrationFingerprint()) {
|
||||
ipcRenderer.send("nativeMessagingReply", { command: "verifyFingerprint", appId: appId });
|
||||
|
||||
const fingerprint = (
|
||||
await this.cryptoService.getFingerprint(
|
||||
await this.stateService.getUserId(),
|
||||
remotePublicKey
|
||||
)
|
||||
).join(" ");
|
||||
|
||||
this.messagingService.send("setFocus");
|
||||
|
||||
// Await confirmation that fingerprint is correct
|
||||
const submitted = await Swal.fire({
|
||||
titleText: this.i18nService.t("verifyBrowserTitle"),
|
||||
html: `${this.i18nService.t("verifyBrowserDesc")}<br><br><strong>${fingerprint}</strong>`,
|
||||
showCancelButton: true,
|
||||
cancelButtonText: this.i18nService.t("cancel"),
|
||||
showConfirmButton: true,
|
||||
confirmButtonText: this.i18nService.t("approve"),
|
||||
allowOutsideClick: false,
|
||||
});
|
||||
|
||||
if (submitted.value !== true) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.secureCommunication(remotePublicKey, appId);
|
||||
return;
|
||||
}
|
||||
|
||||
private async messageHandler(msg: any) {
|
||||
const appId = msg.appId;
|
||||
const rawMessage = msg.message;
|
||||
const message = JSON.parse(
|
||||
await this.cryptoService.decryptToUtf8(rawMessage, this.sharedSecrets.get(appId))
|
||||
);
|
||||
|
||||
// Request to setup secure encryption
|
||||
if (rawMessage.command === 'setupEncryption') {
|
||||
const remotePublicKey = Utils.fromB64ToArray(rawMessage.publicKey).buffer;
|
||||
|
||||
// Valudate the UserId to ensure we are logged into the same account.
|
||||
if (rawMessage.userId !== await this.stateService.getUserId()) {
|
||||
ipcRenderer.send('nativeMessagingReply', {command: 'wrongUserId', appId: appId});
|
||||
return;
|
||||
}
|
||||
|
||||
if (await this.stateService.getEnableBrowserIntegrationFingerprint()) {
|
||||
ipcRenderer.send('nativeMessagingReply', {command: 'verifyFingerprint', appId: appId});
|
||||
|
||||
const fingerprint = (await this.cryptoService.getFingerprint(await this.stateService.getUserId(), remotePublicKey)).join(' ');
|
||||
|
||||
this.messagingService.send('setFocus');
|
||||
|
||||
// Await confirmation that fingerprint is correct
|
||||
const submitted = await Swal.fire({
|
||||
titleText: this.i18nService.t('verifyBrowserTitle'),
|
||||
html: `${this.i18nService.t('verifyBrowserDesc')}<br><br><strong>${fingerprint}</strong>`,
|
||||
showCancelButton: true,
|
||||
cancelButtonText: this.i18nService.t('cancel'),
|
||||
showConfirmButton: true,
|
||||
confirmButtonText: this.i18nService.t('approve'),
|
||||
allowOutsideClick: false,
|
||||
});
|
||||
|
||||
if (submitted.value !== true) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.secureCommunication(remotePublicKey, appId);
|
||||
return;
|
||||
}
|
||||
|
||||
const message = JSON.parse(await this.cryptoService.decryptToUtf8(rawMessage, this.sharedSecrets.get(appId)));
|
||||
|
||||
// Shared secret is invalidated, force re-authentication
|
||||
if (message == null) {
|
||||
ipcRenderer.send('nativeMessagingReply', {command: 'invalidateEncryption', appId: appId});
|
||||
return;
|
||||
}
|
||||
|
||||
if (Math.abs(message.timestamp - Date.now()) > MessageValidTimeout) {
|
||||
this.logService.error('NativeMessage is to old, ignoring.');
|
||||
return;
|
||||
}
|
||||
|
||||
switch (message.command) {
|
||||
case 'biometricUnlock':
|
||||
if (! this.platformUtilService.supportsBiometric()) {
|
||||
return this.send({command: 'biometricUnlock', response: 'not supported'}, appId);
|
||||
}
|
||||
|
||||
if (! await this.vaultTimeoutService.isBiometricLockSet()) {
|
||||
this.send({command: 'biometricUnlock', response: 'not enabled'}, appId);
|
||||
|
||||
return await Swal.fire({
|
||||
title: this.i18nService.t('biometricsNotEnabledTitle'),
|
||||
text: this.i18nService.t('biometricsNotEnabledDesc'),
|
||||
showCancelButton: true,
|
||||
cancelButtonText: this.i18nService.t('cancel'),
|
||||
showConfirmButton: false,
|
||||
});
|
||||
}
|
||||
|
||||
const keyB64 = (await this.cryptoService.getKeyFromStorage(KeySuffixOptions.Biometric)).keyB64;
|
||||
|
||||
if (keyB64 != null) {
|
||||
this.send({ command: 'biometricUnlock', response: 'unlocked', keyB64: keyB64 }, appId);
|
||||
} else {
|
||||
this.send({ command: 'biometricUnlock', response: 'canceled' }, appId);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
this.logService.error('NativeMessage, got unknown command.');
|
||||
}
|
||||
// Shared secret is invalidated, force re-authentication
|
||||
if (message == null) {
|
||||
ipcRenderer.send("nativeMessagingReply", { command: "invalidateEncryption", appId: appId });
|
||||
return;
|
||||
}
|
||||
|
||||
private async send(message: any, appId: string) {
|
||||
message.timestamp = Date.now();
|
||||
|
||||
const encrypted = await this.cryptoService.encrypt(JSON.stringify(message), this.sharedSecrets.get(appId));
|
||||
|
||||
ipcRenderer.send('nativeMessagingReply', {appId: appId, message: encrypted});
|
||||
if (Math.abs(message.timestamp - Date.now()) > MessageValidTimeout) {
|
||||
this.logService.error("NativeMessage is to old, ignoring.");
|
||||
return;
|
||||
}
|
||||
|
||||
private async secureCommunication(remotePublicKey: ArrayBuffer, appId: string) {
|
||||
const secret = await this.cryptoFunctionService.randomBytes(64);
|
||||
this.sharedSecrets.set(appId, new SymmetricCryptoKey(secret));
|
||||
switch (message.command) {
|
||||
case "biometricUnlock":
|
||||
if (!this.platformUtilService.supportsBiometric()) {
|
||||
return this.send({ command: "biometricUnlock", response: "not supported" }, appId);
|
||||
}
|
||||
|
||||
const encryptedSecret = await this.cryptoFunctionService.rsaEncrypt(secret, remotePublicKey, EncryptionAlgorithm);
|
||||
ipcRenderer.send('nativeMessagingReply', {appId: appId, command: 'setupEncryption', sharedSecret: Utils.fromBufferToB64(encryptedSecret)});
|
||||
if (!(await this.vaultTimeoutService.isBiometricLockSet())) {
|
||||
this.send({ command: "biometricUnlock", response: "not enabled" }, appId);
|
||||
|
||||
return await Swal.fire({
|
||||
title: this.i18nService.t("biometricsNotEnabledTitle"),
|
||||
text: this.i18nService.t("biometricsNotEnabledDesc"),
|
||||
showCancelButton: true,
|
||||
cancelButtonText: this.i18nService.t("cancel"),
|
||||
showConfirmButton: false,
|
||||
});
|
||||
}
|
||||
|
||||
const keyB64 = (await this.cryptoService.getKeyFromStorage(KeySuffixOptions.Biometric))
|
||||
.keyB64;
|
||||
|
||||
if (keyB64 != null) {
|
||||
this.send({ command: "biometricUnlock", response: "unlocked", keyB64: keyB64 }, appId);
|
||||
} else {
|
||||
this.send({ command: "biometricUnlock", response: "canceled" }, appId);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
this.logService.error("NativeMessage, got unknown command.");
|
||||
}
|
||||
}
|
||||
|
||||
private async send(message: any, appId: string) {
|
||||
message.timestamp = Date.now();
|
||||
|
||||
const encrypted = await this.cryptoService.encrypt(
|
||||
JSON.stringify(message),
|
||||
this.sharedSecrets.get(appId)
|
||||
);
|
||||
|
||||
ipcRenderer.send("nativeMessagingReply", { appId: appId, message: encrypted });
|
||||
}
|
||||
|
||||
private async secureCommunication(remotePublicKey: ArrayBuffer, appId: string) {
|
||||
const secret = await this.cryptoFunctionService.randomBytes(64);
|
||||
this.sharedSecrets.set(appId, new SymmetricCryptoKey(secret));
|
||||
|
||||
const encryptedSecret = await this.cryptoFunctionService.rsaEncrypt(
|
||||
secret,
|
||||
remotePublicKey,
|
||||
EncryptionAlgorithm
|
||||
);
|
||||
ipcRenderer.send("nativeMessagingReply", {
|
||||
appId: appId,
|
||||
command: "setupEncryption",
|
||||
sharedSecret: Utils.fromBufferToB64(encryptedSecret),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Injectable } from "@angular/core";
|
||||
|
||||
import { PasswordRepromptService as BasePasswordRepromptService } from 'jslib-angular/services/passwordReprompt.service';
|
||||
import { PasswordRepromptComponent } from '../app/components/password-reprompt.component';
|
||||
import { PasswordRepromptService as BasePasswordRepromptService } from "jslib-angular/services/passwordReprompt.service";
|
||||
import { PasswordRepromptComponent } from "../app/components/password-reprompt.component";
|
||||
|
||||
@Injectable()
|
||||
export class PasswordRepromptService extends BasePasswordRepromptService {
|
||||
component = PasswordRepromptComponent;
|
||||
component = PasswordRepromptComponent;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user