[Reset Password] Refactor to use new auth result (#380)

* [Reset Password] Refactor to use new auth result

* Update jslib

* Update class to fix build
This commit is contained in:
Vincent Salucci 2021-10-12 16:51:14 -05:00 committed by GitHub
parent 0803bc2f7b
commit 325e9ded0d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 19 additions and 131 deletions

2
jslib

@ -1 +1 @@
Subproject commit 764dc40b36e0000807e59b8d6feea5ac4577270d
Subproject commit e3ab324d59ee04870007e5078901a22e4dd81440

View File

@ -13,8 +13,6 @@ import { PolicyService } from 'jslib-common/abstractions/policy.service';
import { SyncService } from 'jslib-common/abstractions/sync.service';
import { UserService } from 'jslib-common/abstractions/user.service';
import { UpdateTempPasswordRequest } from 'jslib-common/models/request/updateTempPasswordRequest';
import { MessageResponse } from 'jslib-node/cli/models/response/messageResponse';
import { Utils } from 'jslib-common/misc/utils';
@ -23,16 +21,17 @@ import { LoginCommand as BaseLoginCommand } from 'jslib-node/cli/commands/login.
export class LoginCommand extends BaseLoginCommand {
private options: program.OptionValues;
private email: string;
constructor(authService: AuthService, apiService: ApiService,
cryptoFunctionService: CryptoFunctionService, syncService: SyncService,
i18nService: I18nService, environmentService: EnvironmentService,
passwordGenerationService: PasswordGenerationService, platformUtilsService: PlatformUtilsService,
private userService: UserService, private cryptoService: CryptoService, private policyService: PolicyService,
userService: UserService, cryptoService: CryptoService, policyService: PolicyService,
private logoutCallback: () => Promise<void>) {
super(authService, apiService, i18nService, environmentService, passwordGenerationService,
cryptoFunctionService, platformUtilsService, 'cli');
cryptoFunctionService, platformUtilsService, userService, cryptoService, policyService,
'cli', syncService);
this.logout = this.logoutCallback;
this.validatedParams = async () => {
const key = await cryptoFunctionService.randomBytes(64);
process.env.BW_SESSION = Utils.fromBufferToB64(key);
@ -40,12 +39,21 @@ export class LoginCommand extends BaseLoginCommand {
this.success = async () => {
await syncService.fullSync(true);
this.email = await this.userService.getEmail();
if (await this.userService.getForcePasswordReset()) {
return await this.updateTempPassword();
if ((this.options.sso != null || this.options.apikey != null) && this.canInteract) {
const res = new MessageResponse('You are logged in!', '\n' +
'To unlock your vault, use the `unlock` command. ex:\n' +
'$ bw unlock');
return res;
} else {
const res = new MessageResponse('You are logged in!', '\n' +
'To unlock your vault, set your session key to the `BW_SESSION` environment variable. ex:\n' +
'$ export BW_SESSION="' + process.env.BW_SESSION + '"\n' +
'> $env:BW_SESSION="' + process.env.BW_SESSION + '"\n\n' +
'You can also pass the session key to any command with the `--session` option. ex:\n' +
'$ bw list items --session ' + process.env.BW_SESSION);
res.raw = process.env.BW_SESSION;
return res;
}
return this.deliverResponse();
};
}
@ -54,124 +62,4 @@ export class LoginCommand extends BaseLoginCommand {
this.email = email;
return super.run(email, password, options);
}
private deliverResponse(): MessageResponse {
if ((this.options.sso != null || this.options.apikey != null) && this.canInteract) {
const res = new MessageResponse('You are logged in!', '\n' +
'To unlock your vault, use the `unlock` command. ex:\n' +
'$ bw unlock');
return res;
} else {
const res = new MessageResponse('You are logged in!', '\n' +
'To unlock your vault, set your session key to the `BW_SESSION` environment variable. ex:\n' +
'$ export BW_SESSION="' + process.env.BW_SESSION + '"\n' +
'> $env:BW_SESSION="' + process.env.BW_SESSION + '"\n\n' +
'You can also pass the session key to any command with the `--session` option. ex:\n' +
'$ bw list items --session ' + process.env.BW_SESSION);
res.raw = process.env.BW_SESSION;
return res;
}
}
private async updateTempPassword(error?: string): Promise<MessageResponse> {
// If no interaction available, alert user to use web vault
if (!this.canInteract) {
await this.logoutCallback();
this.authService.logOut(() => { /* Do nothing */ });
return new MessageResponse('An organization administrator recently changed your master password. In order to access the vault, you must update your master password now via the web vault. You have been logged out.', null);
}
// Get New Master Password
const baseMessage = 'An organization administrator recently changed your master password.In order to access the vault, you must update your master password now.\n' + 'Master password: ';
const firstMessage = error != null ? error + baseMessage : baseMessage;
const mp: inquirer.Answers = await inquirer.createPromptModule({ output: process.stderr })({
type: 'password',
name: 'password',
message: firstMessage,
});
const masterPassword = mp.password;
// Master Password Validation
if (masterPassword == null || masterPassword === '') {
return this.updateTempPassword('Master password is required.\n');
}
if (masterPassword.length < 8) {
return this.updateTempPassword('Master password must be at least 8 characters long.\n');
}
// Get New Master Password Re-type
const retype: inquirer.Answers = await inquirer.createPromptModule({ output: process.stderr })({
type: 'password',
name: 'password',
message: 'Re-type New Master password:',
});
const masterPasswordRetype = retype.password;
// Re-type Validation
if (masterPassword !== masterPasswordRetype) {
return this.updateTempPassword('Master password confirmation does not match.\n');
}
// Get Hint (optional)
const hint: inquirer.Answers = await inquirer.createPromptModule({ output: process.stderr })({
type: 'input',
name: 'input',
message: 'Master Password Hint:',
});
const masterPasswordHint = hint.input;
// Retrieve details for key generation
const enforcedPolicyOptions = await this.policyService.getMasterPasswordPolicyOptions();
const kdf = await this.userService.getKdf();
const kdfIterations = await this.userService.getKdfIterations();
// Strength & Policy Validation
const strengthResult = this.passwordGenerationService.passwordStrength(masterPassword,
this.getPasswordStrengthUserInput());
if (enforcedPolicyOptions != null &&
!this.policyService.evaluateMasterPassword(
strengthResult.score,
masterPassword,
enforcedPolicyOptions)) {
return this.updateTempPassword('Your new master password does not meet the policy requirements.\n');
}
try {
// Create new key and hash new password
const newKey = await this.cryptoService.makeKey(masterPassword, this.email.trim().toLowerCase(),
kdf, kdfIterations);
const newPasswordHash = await this.cryptoService.hashPassword(masterPassword, newKey);
// Grab user's current enc key
const userEncKey = await this.cryptoService.getEncKey();
// Create new encKey for the User
const newEncKey = await this.cryptoService.remakeEncKey(newKey, userEncKey);
// Create request
const request = new UpdateTempPasswordRequest();
request.key = newEncKey[1].encryptedString;
request.newMasterPasswordHash = newPasswordHash;
request.masterPasswordHint = masterPasswordHint;
// Update user's password
await this.apiService.putUpdateTempPassword(request);
return this.deliverResponse();
} catch (e) {
await this.logoutCallback();
this.authService.logOut(() => { /* Do nothing */ });
return e;
}
}
private getPasswordStrengthUserInput() {
let userInput: string[] = [];
const atPosition = this.email.indexOf('@');
if (atPosition > -1) {
userInput = userInput.concat(this.email.substr(0, atPosition).trim().toLowerCase().split(/[^A-Za-z0-9]/));
}
return userInput;
}
}