mirror of
https://github.com/bitwarden/browser
synced 2025-12-20 02:03:39 +00:00
Move CLI to apps/cli
This commit is contained in:
20
apps/cli/src/services/i18n.service.ts
Normal file
20
apps/cli/src/services/i18n.service.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
this.supportedTranslationLocales = ["en"];
|
||||
}
|
||||
}
|
||||
40
apps/cli/src/services/lowdbStorage.service.ts
Normal file
40
apps/cli/src/services/lowdbStorage.service.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import * as lock from "proper-lockfile";
|
||||
import { OperationOptions } from "retry";
|
||||
|
||||
import { LogService } from "jslib-common/abstractions/log.service";
|
||||
import { Utils } from "jslib-common/misc/utils";
|
||||
import { LowdbStorageService as LowdbStorageServiceBase } from "jslib-node/services/lowdbStorage.service";
|
||||
|
||||
const retries: OperationOptions = {
|
||||
retries: 50,
|
||||
minTimeout: 100,
|
||||
maxTimeout: 250,
|
||||
factor: 2,
|
||||
};
|
||||
|
||||
export class LowdbStorageService extends LowdbStorageServiceBase {
|
||||
constructor(
|
||||
logService: LogService,
|
||||
defaults?: any,
|
||||
dir?: string,
|
||||
allowCache = false,
|
||||
private requireLock = false
|
||||
) {
|
||||
super(logService, defaults, dir, allowCache);
|
||||
}
|
||||
|
||||
protected async lockDbFile<T>(action: () => T): Promise<T> {
|
||||
if (this.requireLock && !Utils.isNullOrWhitespace(this.dataFilePath)) {
|
||||
this.logService.info("acquiring db file lock");
|
||||
return await lock.lock(this.dataFilePath, { retries: retries }).then((release) => {
|
||||
try {
|
||||
return action();
|
||||
} finally {
|
||||
release();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return action();
|
||||
}
|
||||
}
|
||||
}
|
||||
103
apps/cli/src/services/nodeEnvSecureStorage.service.ts
Normal file
103
apps/cli/src/services/nodeEnvSecureStorage.service.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||
import { LogService } from "jslib-common/abstractions/log.service";
|
||||
import { StorageService } from "jslib-common/abstractions/storage.service";
|
||||
import { Utils } from "jslib-common/misc/utils";
|
||||
import { SymmetricCryptoKey } from "jslib-common/models/domain/symmetricCryptoKey";
|
||||
|
||||
export class NodeEnvSecureStorageService implements StorageService {
|
||||
constructor(
|
||||
private storageService: StorageService,
|
||||
private logService: LogService,
|
||||
private cryptoService: () => CryptoService
|
||||
) {}
|
||||
|
||||
async get<T>(key: string): Promise<T> {
|
||||
const value = await this.storageService.get<string>(this.makeProtectedStorageKey(key));
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
const obj = await this.decrypt(value);
|
||||
return obj as any;
|
||||
}
|
||||
|
||||
async has(key: string): Promise<boolean> {
|
||||
return (await this.get(key)) != null;
|
||||
}
|
||||
|
||||
async save(key: string, obj: any): Promise<any> {
|
||||
if (obj == null) {
|
||||
return this.remove(key);
|
||||
}
|
||||
|
||||
if (obj !== null && typeof obj !== "string") {
|
||||
throw new Error("Only string storage is allowed.");
|
||||
}
|
||||
const protectedObj = await this.encrypt(obj);
|
||||
await this.storageService.save(this.makeProtectedStorageKey(key), protectedObj);
|
||||
}
|
||||
|
||||
remove(key: string): Promise<any> {
|
||||
return this.storageService.remove(this.makeProtectedStorageKey(key));
|
||||
}
|
||||
|
||||
private async encrypt(plainValue: string): Promise<string> {
|
||||
const sessionKey = this.getSessionKey();
|
||||
if (sessionKey == null) {
|
||||
throw new Error("No session key available.");
|
||||
}
|
||||
const encValue = await this.cryptoService().encryptToBytes(
|
||||
Utils.fromB64ToArray(plainValue).buffer,
|
||||
sessionKey
|
||||
);
|
||||
if (encValue == null) {
|
||||
throw new Error("Value didn't encrypt.");
|
||||
}
|
||||
|
||||
return Utils.fromBufferToB64(encValue.buffer);
|
||||
}
|
||||
|
||||
private async decrypt(encValue: string): Promise<string> {
|
||||
try {
|
||||
const sessionKey = this.getSessionKey();
|
||||
if (sessionKey == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const decValue = await this.cryptoService().decryptFromBytes(
|
||||
Utils.fromB64ToArray(encValue).buffer,
|
||||
sessionKey
|
||||
);
|
||||
if (decValue == null) {
|
||||
this.logService.info("Failed to decrypt.");
|
||||
return null;
|
||||
}
|
||||
|
||||
return Utils.fromBufferToB64(decValue);
|
||||
} catch (e) {
|
||||
this.logService.info("Decrypt error.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private getSessionKey() {
|
||||
try {
|
||||
if (process.env.BW_SESSION != null) {
|
||||
const sessionBuffer = Utils.fromB64ToArray(process.env.BW_SESSION).buffer;
|
||||
if (sessionBuffer != null) {
|
||||
const sessionKey = new SymmetricCryptoKey(sessionBuffer);
|
||||
if (sessionBuffer != null) {
|
||||
return sessionKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
this.logService.info("Session key is invalid.");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private makeProtectedStorageKey(key: string) {
|
||||
return "__PROTECTED__" + key;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user