mirror of
https://github.com/bitwarden/browser
synced 2025-12-20 18:23:31 +00:00
Merge branch 'master' into feature/flexible-collections
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@bitwarden/cli",
|
||||
"description": "A secure and free password manager for all of your devices.",
|
||||
"version": "2023.7.0",
|
||||
"version": "2023.8.2",
|
||||
"keywords": [
|
||||
"bitwarden",
|
||||
"password",
|
||||
@@ -49,29 +49,29 @@
|
||||
"dependencies": {
|
||||
"@koa/multer": "3.0.2",
|
||||
"@koa/router": "12.0.0",
|
||||
"argon2": "0.30.3",
|
||||
"argon2": "0.31.0",
|
||||
"big-integer": "1.6.51",
|
||||
"browser-hrtime": "1.1.8",
|
||||
"chalk": "4.1.2",
|
||||
"commander": "7.2.0",
|
||||
"form-data": "4.0.0",
|
||||
"https-proxy-agent": "5.0.1",
|
||||
"inquirer": "8.2.5",
|
||||
"inquirer": "8.2.6",
|
||||
"jsdom": "22.1.0",
|
||||
"jszip": "3.10.1",
|
||||
"koa": "2.14.2",
|
||||
"koa-bodyparser": "4.4.0",
|
||||
"koa-bodyparser": "4.4.1",
|
||||
"koa-json": "2.0.2",
|
||||
"lowdb": "1.0.0",
|
||||
"lunr": "2.3.9",
|
||||
"multer": "1.4.5-lts.1",
|
||||
"node-fetch": "2.6.11",
|
||||
"node-fetch": "2.6.12",
|
||||
"node-forge": "1.3.1",
|
||||
"open": "8.4.2",
|
||||
"papaparse": "5.4.1",
|
||||
"proper-lockfile": "4.1.2",
|
||||
"rxjs": "7.8.1",
|
||||
"tldts": "6.0.5",
|
||||
"tldts": "6.0.14",
|
||||
"zxcvbn": "4.4.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service";
|
||||
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
|
||||
|
||||
import { Response } from "../../models/response";
|
||||
import { MessageResponse } from "../../models/response/message.response";
|
||||
|
||||
@@ -406,15 +406,15 @@ export class LoginCommand {
|
||||
}
|
||||
|
||||
try {
|
||||
const { newPasswordHash, newEncKey, hint } = await this.collectNewMasterPasswordDetails(
|
||||
const { newPasswordHash, newUserKey, hint } = await this.collectNewMasterPasswordDetails(
|
||||
"Your master password does not meet one or more of your organization policies. In order to access the vault, you must update your master password now."
|
||||
);
|
||||
|
||||
const request = new PasswordRequest();
|
||||
request.masterPasswordHash = await this.cryptoService.hashPassword(currentPassword, null);
|
||||
request.masterPasswordHash = await this.cryptoService.hashMasterKey(currentPassword, null);
|
||||
request.masterPasswordHint = hint;
|
||||
request.newMasterPasswordHash = newPasswordHash;
|
||||
request.key = newEncKey[1].encryptedString;
|
||||
request.key = newUserKey[1].encryptedString;
|
||||
|
||||
await this.apiService.postPassword(request);
|
||||
|
||||
@@ -444,12 +444,12 @@ export class LoginCommand {
|
||||
}
|
||||
|
||||
try {
|
||||
const { newPasswordHash, newEncKey, hint } = await this.collectNewMasterPasswordDetails(
|
||||
const { newPasswordHash, newUserKey, hint } = await this.collectNewMasterPasswordDetails(
|
||||
"An organization administrator recently changed your master password. In order to access the vault, you must update your master password now."
|
||||
);
|
||||
|
||||
const request = new UpdateTempPasswordRequest();
|
||||
request.key = newEncKey[1].encryptedString;
|
||||
request.key = newUserKey[1].encryptedString;
|
||||
request.newMasterPasswordHash = newPasswordHash;
|
||||
request.masterPasswordHint = hint;
|
||||
|
||||
@@ -467,8 +467,8 @@ export class LoginCommand {
|
||||
|
||||
/**
|
||||
* Collect new master password and hint from the CLI. The collected password
|
||||
* is validated against any applicable master password policies and a new encryption
|
||||
* key is generated
|
||||
* is validated against any applicable master password policies, a new master
|
||||
* key is generated, and we use it to re-encrypt the user key
|
||||
* @param prompt - Message that is displayed during the initial prompt
|
||||
* @param error
|
||||
*/
|
||||
@@ -477,7 +477,7 @@ export class LoginCommand {
|
||||
error?: string
|
||||
): Promise<{
|
||||
newPasswordHash: string;
|
||||
newEncKey: [SymmetricCryptoKey, EncString];
|
||||
newUserKey: [SymmetricCryptoKey, EncString];
|
||||
hint?: string;
|
||||
}> {
|
||||
if (this.email == null || this.email === "undefined") {
|
||||
@@ -559,21 +559,24 @@ export class LoginCommand {
|
||||
const kdfConfig = await this.stateService.getKdfConfig();
|
||||
|
||||
// Create new key and hash new password
|
||||
const newKey = await this.cryptoService.makeKey(
|
||||
const newMasterKey = await this.cryptoService.makeMasterKey(
|
||||
masterPassword,
|
||||
this.email.trim().toLowerCase(),
|
||||
kdf,
|
||||
kdfConfig
|
||||
);
|
||||
const newPasswordHash = await this.cryptoService.hashPassword(masterPassword, newKey);
|
||||
const newPasswordHash = await this.cryptoService.hashMasterKey(masterPassword, newMasterKey);
|
||||
|
||||
// Grab user's current enc key
|
||||
const userEncKey = await this.cryptoService.getEncKey();
|
||||
// Grab user key
|
||||
const userKey = await this.cryptoService.getUserKey();
|
||||
if (!userKey) {
|
||||
throw new Error("User key not found.");
|
||||
}
|
||||
|
||||
// Create new encKey for the User
|
||||
const newEncKey = await this.cryptoService.remakeEncKey(newKey, userEncKey);
|
||||
// Re-encrypt user key with new master key
|
||||
const newUserKey = await this.cryptoService.encryptUserKeyWithMasterKey(newMasterKey, userKey);
|
||||
|
||||
return { newPasswordHash, newEncKey, hint: masterPasswordHint };
|
||||
return { newPasswordHash, newUserKey: newUserKey, hint: masterPasswordHint };
|
||||
}
|
||||
|
||||
private async handleCaptchaRequired(
|
||||
|
||||
@@ -44,17 +44,17 @@ export class UnlockCommand {
|
||||
const email = await this.stateService.getEmail();
|
||||
const kdf = await this.stateService.getKdfType();
|
||||
const kdfConfig = await this.stateService.getKdfConfig();
|
||||
const key = await this.cryptoService.makeKey(password, email, kdf, kdfConfig);
|
||||
const storedKeyHash = await this.cryptoService.getKeyHash();
|
||||
const masterKey = await this.cryptoService.makeMasterKey(password, email, kdf, kdfConfig);
|
||||
const storedKeyHash = await this.cryptoService.getMasterKeyHash();
|
||||
|
||||
let passwordValid = false;
|
||||
if (key != null) {
|
||||
if (masterKey != null) {
|
||||
if (storedKeyHash != null) {
|
||||
passwordValid = await this.cryptoService.compareAndUpdateKeyHash(password, key);
|
||||
passwordValid = await this.cryptoService.compareAndUpdateKeyHash(password, masterKey);
|
||||
} else {
|
||||
const serverKeyHash = await this.cryptoService.hashPassword(
|
||||
const serverKeyHash = await this.cryptoService.hashMasterKey(
|
||||
password,
|
||||
key,
|
||||
masterKey,
|
||||
HashPurpose.ServerAuthorization
|
||||
);
|
||||
const request = new SecretVerificationRequest();
|
||||
@@ -62,12 +62,12 @@ export class UnlockCommand {
|
||||
try {
|
||||
await this.apiService.postAccountVerifyPassword(request);
|
||||
passwordValid = true;
|
||||
const localKeyHash = await this.cryptoService.hashPassword(
|
||||
const localKeyHash = await this.cryptoService.hashMasterKey(
|
||||
password,
|
||||
key,
|
||||
masterKey,
|
||||
HashPurpose.LocalAuthorization
|
||||
);
|
||||
await this.cryptoService.setKeyHash(localKeyHash);
|
||||
await this.cryptoService.setMasterKeyHash(localKeyHash);
|
||||
} catch {
|
||||
// Ignore
|
||||
}
|
||||
@@ -75,7 +75,9 @@ export class UnlockCommand {
|
||||
}
|
||||
|
||||
if (passwordValid) {
|
||||
await this.cryptoService.setKey(key);
|
||||
await this.cryptoService.setMasterKey(masterKey);
|
||||
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(masterKey);
|
||||
await this.cryptoService.setUserKey(userKey);
|
||||
|
||||
if (await this.keyConnectorService.getConvertAccountRequired()) {
|
||||
const convertToKeyConnectorCommand = new ConvertToKeyConnectorCommand(
|
||||
|
||||
@@ -12,7 +12,13 @@ import { OrganizationService } from "@bitwarden/common/admin-console/services/or
|
||||
import { PolicyApiService } from "@bitwarden/common/admin-console/services/policy/policy-api.service";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/services/policy/policy.service";
|
||||
import { ProviderService } from "@bitwarden/common/admin-console/services/provider.service";
|
||||
import { AuthRequestCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth-request-crypto.service.abstraction";
|
||||
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
||||
import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction";
|
||||
import { AuthRequestCryptoServiceImplementation } from "@bitwarden/common/auth/services/auth-request-crypto.service.implementation";
|
||||
import { AuthService } from "@bitwarden/common/auth/services/auth.service";
|
||||
import { DeviceTrustCryptoService } from "@bitwarden/common/auth/services/device-trust-crypto.service.implementation";
|
||||
import { DevicesApiServiceImplementation } from "@bitwarden/common/auth/services/devices-api.service.implementation";
|
||||
import { KeyConnectorService } from "@bitwarden/common/auth/services/key-connector.service";
|
||||
import { TokenService } from "@bitwarden/common/auth/services/token.service";
|
||||
import { TwoFactorService } from "@bitwarden/common/auth/services/two-factor.service";
|
||||
@@ -31,15 +37,14 @@ import { EnvironmentService } from "@bitwarden/common/platform/services/environm
|
||||
import { FileUploadService } from "@bitwarden/common/platform/services/file-upload/file-upload.service";
|
||||
import { MemoryStorageService } from "@bitwarden/common/platform/services/memory-storage.service";
|
||||
import { NoopMessagingService } from "@bitwarden/common/platform/services/noop-messaging.service";
|
||||
import { StateMigrationService } from "@bitwarden/common/platform/services/state-migration.service";
|
||||
import { StateService } from "@bitwarden/common/platform/services/state.service";
|
||||
import { AuditService } from "@bitwarden/common/services/audit.service";
|
||||
import { OrganizationUserServiceImplementation } from "@bitwarden/common/services/organization-user/organization-user.service.implementation";
|
||||
import { SearchService } from "@bitwarden/common/services/search.service";
|
||||
import { SettingsService } from "@bitwarden/common/services/settings.service";
|
||||
import { TotpService } from "@bitwarden/common/services/totp.service";
|
||||
import { VaultTimeoutService } from "@bitwarden/common/services/vaultTimeout/vaultTimeout.service";
|
||||
import { VaultTimeoutSettingsService } from "@bitwarden/common/services/vaultTimeout/vaultTimeoutSettings.service";
|
||||
import { VaultTimeoutSettingsService } from "@bitwarden/common/services/vault-timeout/vault-timeout-settings.service";
|
||||
import { VaultTimeoutService } from "@bitwarden/common/services/vault-timeout/vault-timeout.service";
|
||||
import {
|
||||
PasswordGenerationService,
|
||||
PasswordGenerationServiceAbstraction,
|
||||
@@ -130,7 +135,6 @@ export class Main {
|
||||
keyConnectorService: KeyConnectorService;
|
||||
userVerificationService: UserVerificationService;
|
||||
stateService: StateService;
|
||||
stateMigrationService: StateMigrationService;
|
||||
organizationService: OrganizationService;
|
||||
providerService: ProviderService;
|
||||
twoFactorService: TwoFactorService;
|
||||
@@ -140,6 +144,9 @@ export class Main {
|
||||
organizationApiService: OrganizationApiServiceAbstraction;
|
||||
syncNotifierService: SyncNotifierService;
|
||||
sendApiService: SendApiService;
|
||||
devicesApiService: DevicesApiServiceAbstraction;
|
||||
deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction;
|
||||
authRequestCryptoService: AuthRequestCryptoServiceAbstraction;
|
||||
|
||||
constructor() {
|
||||
let p = null;
|
||||
@@ -179,18 +186,11 @@ export class Main {
|
||||
|
||||
this.memoryStorageService = new MemoryStorageService();
|
||||
|
||||
this.stateMigrationService = new StateMigrationService(
|
||||
this.storageService,
|
||||
this.secureStorageService,
|
||||
new StateFactory(GlobalState, Account)
|
||||
);
|
||||
|
||||
this.stateService = new StateService(
|
||||
this.storageService,
|
||||
this.secureStorageService,
|
||||
this.memoryStorageService,
|
||||
this.logService,
|
||||
this.stateMigrationService,
|
||||
new StateFactory(GlobalState, Account)
|
||||
);
|
||||
|
||||
@@ -315,6 +315,20 @@ export class Main {
|
||||
this.stateService
|
||||
);
|
||||
|
||||
this.devicesApiService = new DevicesApiServiceImplementation(this.apiService);
|
||||
this.deviceTrustCryptoService = new DeviceTrustCryptoService(
|
||||
this.cryptoFunctionService,
|
||||
this.cryptoService,
|
||||
this.encryptService,
|
||||
this.stateService,
|
||||
this.appIdService,
|
||||
this.devicesApiService,
|
||||
this.i18nService,
|
||||
this.platformUtilsService
|
||||
);
|
||||
|
||||
this.authRequestCryptoService = new AuthRequestCryptoServiceImplementation(this.cryptoService);
|
||||
|
||||
this.authService = new AuthService(
|
||||
this.cryptoService,
|
||||
this.apiService,
|
||||
@@ -330,17 +344,27 @@ export class Main {
|
||||
this.i18nService,
|
||||
this.encryptService,
|
||||
this.passwordStrengthService,
|
||||
this.policyService
|
||||
this.policyService,
|
||||
this.deviceTrustCryptoService,
|
||||
this.authRequestCryptoService
|
||||
);
|
||||
|
||||
const lockedCallback = async () =>
|
||||
await this.cryptoService.clearStoredKey(KeySuffixOptions.Auto);
|
||||
const lockedCallback = async (userId?: string) =>
|
||||
await this.cryptoService.clearStoredUserKey(KeySuffixOptions.Auto);
|
||||
|
||||
this.userVerificationService = new UserVerificationService(
|
||||
this.stateService,
|
||||
this.cryptoService,
|
||||
this.i18nService,
|
||||
this.userVerificationApiService
|
||||
);
|
||||
|
||||
this.vaultTimeoutSettingsService = new VaultTimeoutSettingsService(
|
||||
this.cryptoService,
|
||||
this.tokenService,
|
||||
this.policyService,
|
||||
this.stateService
|
||||
this.stateService,
|
||||
this.userVerificationService
|
||||
);
|
||||
|
||||
this.vaultTimeoutService = new VaultTimeoutService(
|
||||
@@ -351,7 +375,6 @@ export class Main {
|
||||
this.platformUtilsService,
|
||||
this.messagingService,
|
||||
this.searchService,
|
||||
this.keyConnectorService,
|
||||
this.stateService,
|
||||
this.authService,
|
||||
this.vaultTimeoutSettingsService,
|
||||
@@ -406,12 +429,6 @@ export class Main {
|
||||
this.sendProgram = new SendProgram(this);
|
||||
|
||||
this.userVerificationApiService = new UserVerificationApiService(this.apiService);
|
||||
|
||||
this.userVerificationService = new UserVerificationService(
|
||||
this.cryptoService,
|
||||
this.i18nService,
|
||||
this.userVerificationApiService
|
||||
);
|
||||
}
|
||||
|
||||
async run() {
|
||||
|
||||
@@ -5,7 +5,6 @@ import * as koa from "koa";
|
||||
import * as koaBodyParser from "koa-bodyparser";
|
||||
import * as koaJson from "koa-json";
|
||||
|
||||
import { KeySuffixOptions } from "@bitwarden/common/enums";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
|
||||
import { ConfirmCommand } from "../admin-console/commands/confirm.command";
|
||||
@@ -425,11 +424,7 @@ export class ServeCommand {
|
||||
this.processResponse(res, Response.error("You are not logged in."));
|
||||
return true;
|
||||
}
|
||||
if (await this.main.cryptoService.hasKeyInMemory()) {
|
||||
return false;
|
||||
} else if (await this.main.cryptoService.hasKeyStored(KeySuffixOptions.Auto)) {
|
||||
// load key into memory
|
||||
await this.main.cryptoService.getKey();
|
||||
if (await this.main.cryptoService.hasUserKey()) {
|
||||
return false;
|
||||
}
|
||||
this.processResponse(res, Response.error("Vault is locked."));
|
||||
|
||||
@@ -46,5 +46,8 @@
|
||||
},
|
||||
"ssoKeyConnectorError": {
|
||||
"message": "Key Connector error: make sure Key Connector is available and working correctly."
|
||||
},
|
||||
"unsupportedEncryptedImport": {
|
||||
"message": "Importing encrypted files is currently not supported."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import * as chalk from "chalk";
|
||||
import * as program from "commander";
|
||||
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
import { KeySuffixOptions } from "@bitwarden/common/enums";
|
||||
|
||||
import { LockCommand } from "./auth/commands/lock.command";
|
||||
import { LoginCommand } from "./auth/commands/login.command";
|
||||
@@ -299,9 +298,12 @@ export class Program {
|
||||
.option("-p, --passphrase", "Generate a passphrase.")
|
||||
.option("--length <length>", "Length of the password.")
|
||||
.option("--words <words>", "Number of words.")
|
||||
.option("--minNumber <count>", "Minimum number of numeric characters.")
|
||||
.option("--minSpecial <count>", "Minimum number of special characters.")
|
||||
.option("--separator <separator>", "Word separator.")
|
||||
.option("-c, --capitalize", "Title case passphrase.")
|
||||
.option("--includeNumber", "Passphrase includes number.")
|
||||
.option("--ambiguous", "Avoid ambiguous characters.")
|
||||
.on("--help", () => {
|
||||
writeLn("\n Notes:");
|
||||
writeLn("");
|
||||
@@ -597,11 +599,8 @@ export class Program {
|
||||
|
||||
protected async exitIfLocked() {
|
||||
await this.exitIfNotAuthed();
|
||||
if (await this.main.cryptoService.hasKeyInMemory()) {
|
||||
if (await this.main.cryptoService.hasUserKey()) {
|
||||
return;
|
||||
} else if (await this.main.cryptoService.hasKeyStored(KeySuffixOptions.Auto)) {
|
||||
// load key into memory
|
||||
await this.main.cryptoService.getKey();
|
||||
} else if (process.env.BW_NOINTERACTION !== "true") {
|
||||
// must unlock
|
||||
if (await this.main.keyConnectorService.getUsesKeyConnector()) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||
import { PasswordGeneratorOptions } from "@bitwarden/common/tools/generator/password/password-generator-options";
|
||||
|
||||
import { Response } from "../models/response";
|
||||
import { StringResponse } from "../models/response/string.response";
|
||||
@@ -13,7 +14,7 @@ export class GenerateCommand {
|
||||
|
||||
async run(cmdOptions: Record<string, any>): Promise<Response> {
|
||||
const normalizedOptions = new Options(cmdOptions);
|
||||
const options = {
|
||||
const options: PasswordGeneratorOptions = {
|
||||
uppercase: normalizedOptions.uppercase,
|
||||
lowercase: normalizedOptions.lowercase,
|
||||
number: normalizedOptions.number,
|
||||
@@ -24,6 +25,9 @@ export class GenerateCommand {
|
||||
numWords: normalizedOptions.words,
|
||||
capitalize: normalizedOptions.capitalize,
|
||||
includeNumber: normalizedOptions.includeNumber,
|
||||
minNumber: normalizedOptions.minNumber,
|
||||
minSpecial: normalizedOptions.minSpecial,
|
||||
ambiguous: normalizedOptions.ambiguous,
|
||||
};
|
||||
|
||||
const enforcedOptions = (await this.stateService.getIsAuthenticated())
|
||||
@@ -47,6 +51,9 @@ class Options {
|
||||
words: number;
|
||||
capitalize: boolean;
|
||||
includeNumber: boolean;
|
||||
minNumber: number;
|
||||
minSpecial: number;
|
||||
ambiguous: boolean;
|
||||
|
||||
constructor(passedOptions: Record<string, any>) {
|
||||
this.uppercase = CliUtils.convertBooleanOption(passedOptions?.uppercase);
|
||||
@@ -55,10 +62,13 @@ class Options {
|
||||
this.special = CliUtils.convertBooleanOption(passedOptions?.special);
|
||||
this.capitalize = CliUtils.convertBooleanOption(passedOptions?.capitalize);
|
||||
this.includeNumber = CliUtils.convertBooleanOption(passedOptions?.includeNumber);
|
||||
this.length = passedOptions?.length != null ? parseInt(passedOptions?.length, null) : 14;
|
||||
this.ambiguous = CliUtils.convertBooleanOption(passedOptions?.ambiguous);
|
||||
this.length = CliUtils.convertNumberOption(passedOptions?.length, 14);
|
||||
this.type = passedOptions?.passphrase ? "passphrase" : "password";
|
||||
this.separator = passedOptions?.separator == null ? "-" : passedOptions.separator + "";
|
||||
this.words = passedOptions?.words != null ? parseInt(passedOptions.words, null) : 3;
|
||||
this.separator = CliUtils.convertStringOption(passedOptions?.separator, "-");
|
||||
this.words = CliUtils.convertNumberOption(passedOptions?.words, 3);
|
||||
this.minNumber = CliUtils.convertNumberOption(passedOptions?.minNumber, 1);
|
||||
this.minSpecial = CliUtils.convertNumberOption(passedOptions?.minSpecial, 1);
|
||||
|
||||
if (!this.uppercase && !this.lowercase && !this.special && !this.number) {
|
||||
this.lowercase = true;
|
||||
|
||||
@@ -67,7 +67,9 @@ export class ImportCommand {
|
||||
try {
|
||||
let contents;
|
||||
if (format === "1password1pux") {
|
||||
contents = await CliUtils.extract1PuxContent(filepath);
|
||||
contents = await CliUtils.extractZipContent(filepath, "export.data");
|
||||
} else if (format === "protonpass" && filepath.endsWith(".zip")) {
|
||||
contents = await CliUtils.extractZipContent(filepath, "Proton Pass/data.json");
|
||||
} else {
|
||||
contents = await CliUtils.readFile(filepath);
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ export class CliUtils {
|
||||
});
|
||||
}
|
||||
|
||||
static extract1PuxContent(input: string): Promise<string> {
|
||||
static extractZipContent(input: string, filepath: string): Promise<string> {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
let p: string = null;
|
||||
if (input != null && input !== "") {
|
||||
@@ -65,7 +65,7 @@ export class CliUtils {
|
||||
}
|
||||
JSZip.loadAsync(data).then(
|
||||
(zip) => {
|
||||
resolve(zip.file("export.data").async("string"));
|
||||
resolve(zip.file(filepath).async("string"));
|
||||
},
|
||||
(reason) => {
|
||||
reject(reason);
|
||||
@@ -74,6 +74,7 @@ export class CliUtils {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the given data to a file and determine the target file if necessary.
|
||||
* If output is non-empty, it is used as target filename. Otherwise the target filename is
|
||||
@@ -252,4 +253,20 @@ export class CliUtils {
|
||||
static convertBooleanOption(optionValue: any) {
|
||||
return optionValue || optionValue === "" ? true : false;
|
||||
}
|
||||
|
||||
static convertNumberOption(optionValue: any, defaultValue: number) {
|
||||
try {
|
||||
if (optionValue != null) {
|
||||
const numVal = parseInt(optionValue);
|
||||
return !Number.isNaN(numVal) ? numVal : defaultValue;
|
||||
}
|
||||
return defaultValue;
|
||||
} catch {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
static convertStringOption(optionValue: any, defaultValue: string) {
|
||||
return optionValue != null ? String(optionValue) : defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,8 +126,8 @@ export class CreateCommand {
|
||||
return Response.error("Premium status is required to use this feature.");
|
||||
}
|
||||
|
||||
const encKey = await this.cryptoService.getEncKey();
|
||||
if (encKey == null) {
|
||||
const userKey = await this.cryptoService.getUserKey();
|
||||
if (userKey == null) {
|
||||
return Response.error(
|
||||
"You must update your encryption key before you can use this feature. " +
|
||||
"See https://help.bitwarden.com/article/update-encryption-key/"
|
||||
|
||||
Reference in New Issue
Block a user