bitwarden-estensione-browser/apps/cli/src/services/nodeEnvSecureStorage.servic...

104 lines
2.9 KiB
TypeScript
Raw Normal View History

2021-12-20 18:04:00 +01:00
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";
2022-03-03 18:24:41 +01:00
import { SymmetricCryptoKey } from "jslib-common/models/domain/symmetricCryptoKey";
2018-05-16 03:11:58 +02:00
export class NodeEnvSecureStorageService implements StorageService {
2021-12-20 18:04:00 +01:00
constructor(
private storageService: StorageService,
private logService: LogService,
private cryptoService: () => CryptoService
) {}
2018-05-16 03:11:58 +02:00
2021-12-20 18:04:00 +01:00
async get<T>(key: string): Promise<T> {
const value = await this.storageService.get<string>(this.makeProtectedStorageKey(key));
if (value == null) {
return null;
}
2021-12-20 18:04:00 +01:00
const obj = await this.decrypt(value);
return obj as any;
}
2021-12-20 18:04:00 +01:00
async has(key: string): Promise<boolean> {
return (await this.get(key)) != null;
}
2018-05-16 03:11:58 +02:00
2021-12-20 18:04:00 +01:00
async save(key: string, obj: any): Promise<any> {
if (obj == null) {
return this.remove(key);
}
if (obj !== null && typeof obj !== "string") {
2021-12-20 18:04:00 +01:00
throw new Error("Only string storage is allowed.");
2018-05-16 03:11:58 +02:00
}
2021-12-20 18:04:00 +01:00
const protectedObj = await this.encrypt(obj);
await this.storageService.save(this.makeProtectedStorageKey(key), protectedObj);
}
2018-05-16 03:11:58 +02:00
2021-12-20 18:04:00 +01:00
remove(key: string): Promise<any> {
return this.storageService.remove(this.makeProtectedStorageKey(key));
}
2018-05-16 03:11:58 +02:00
2021-12-20 18:04:00 +01:00
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.");
2018-05-16 03:11:58 +02:00
}
2021-12-20 18:04:00 +01:00
return Utils.fromBufferToB64(encValue.buffer);
}
2018-05-16 03:11:58 +02:00
2021-12-20 18:04:00 +01:00
private async decrypt(encValue: string): Promise<string> {
try {
const sessionKey = this.getSessionKey();
if (sessionKey == null) {
return null;
}
2018-05-16 03:11:58 +02:00
2021-12-20 18:04:00 +01:00
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;
2018-05-16 03:11:58 +02:00
}
2021-12-20 18:04:00 +01:00
}
2018-05-16 03:11:58 +02:00
2021-12-20 18:04:00 +01:00
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;
}
2018-05-16 03:11:58 +02:00
}
2021-12-20 18:04:00 +01:00
}
} catch (e) {
this.logService.info("Session key is invalid.");
2018-05-16 03:11:58 +02:00
}
2021-12-20 18:04:00 +01:00
return null;
}
private makeProtectedStorageKey(key: string) {
return "__PROTECTED__" + key;
}
2018-05-16 03:11:58 +02:00
}