mirror of
https://github.com/bitwarden/browser.git
synced 2025-02-08 00:01:28 +01:00
use shared login/logout commands
This commit is contained in:
parent
a74bf65f73
commit
b846ce3f89
2
jslib
2
jslib
@ -1 +1 @@
|
||||
Subproject commit b5b4222b325a5fab7fabfd53f23de1876ffccec8
|
||||
Subproject commit d4c2b20a2594fcac1fdabf312b7289657b4af0c8
|
@ -1,138 +1,26 @@
|
||||
import * as program from 'commander';
|
||||
import * as inquirer from 'inquirer';
|
||||
|
||||
import { TwoFactorProviderType } from 'jslib/enums/twoFactorProviderType';
|
||||
|
||||
import { AuthResult } from 'jslib/models/domain/authResult';
|
||||
import { TwoFactorEmailRequest } from 'jslib/models/request/twoFactorEmailRequest';
|
||||
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { AuthService } from 'jslib/abstractions/auth.service';
|
||||
import { CryptoFunctionService } from 'jslib/abstractions/cryptoFunction.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { SyncService } from 'jslib/abstractions/sync.service';
|
||||
|
||||
import { Response } from 'jslib/cli/models/response';
|
||||
import { MessageResponse } from 'jslib/cli/models/response/messageResponse';
|
||||
|
||||
import { Utils } from 'jslib/misc/utils';
|
||||
|
||||
export class LoginCommand {
|
||||
constructor(private authService: AuthService, private apiService: ApiService,
|
||||
private cryptoFunctionService: CryptoFunctionService, private syncService: SyncService) { }
|
||||
import { LoginCommand as BaseLoginCommand } from 'jslib/cli/commands/login.command';
|
||||
|
||||
async run(email: string, password: string, cmd: program.Command) {
|
||||
if (email == null || email === '') {
|
||||
const answer: inquirer.Answers = await inquirer.createPromptModule({ output: process.stderr })({
|
||||
type: 'input',
|
||||
name: 'email',
|
||||
message: 'Email address:',
|
||||
});
|
||||
email = answer.email;
|
||||
}
|
||||
if (email == null || email.trim() === '') {
|
||||
return Response.badRequest('Email address is required.');
|
||||
}
|
||||
if (email.indexOf('@') === -1) {
|
||||
return Response.badRequest('Email address is invalid.');
|
||||
}
|
||||
|
||||
if (password == null || password === '') {
|
||||
const answer: inquirer.Answers = await inquirer.createPromptModule({ output: process.stderr })({
|
||||
type: 'password',
|
||||
name: 'password',
|
||||
message: 'Master password:',
|
||||
});
|
||||
password = answer.password;
|
||||
}
|
||||
if (password == null || password === '') {
|
||||
return Response.badRequest('Master password is required.');
|
||||
}
|
||||
|
||||
let twoFactorToken: string = cmd.code;
|
||||
let twoFactorMethod: TwoFactorProviderType = null;
|
||||
try {
|
||||
if (cmd.method != null) {
|
||||
twoFactorMethod = parseInt(cmd.method, null);
|
||||
}
|
||||
} catch (e) {
|
||||
return Response.error('Invalid two-step login method.');
|
||||
}
|
||||
|
||||
try {
|
||||
await this.setNewSessionKey();
|
||||
let response: AuthResult = null;
|
||||
if (twoFactorToken != null && twoFactorMethod != null) {
|
||||
response = await this.authService.logInComplete(email, password, twoFactorMethod,
|
||||
twoFactorToken, false);
|
||||
} else {
|
||||
response = await this.authService.logIn(email, password);
|
||||
if (response.twoFactor) {
|
||||
let selectedProvider: any = null;
|
||||
const twoFactorProviders = this.authService.getSupportedTwoFactorProviders(null);
|
||||
if (twoFactorProviders.length === 0) {
|
||||
return Response.badRequest('No providers available for this client.');
|
||||
}
|
||||
|
||||
if (twoFactorMethod != null) {
|
||||
try {
|
||||
selectedProvider = twoFactorProviders.filter((p) => p.type === twoFactorMethod)[0];
|
||||
} catch (e) {
|
||||
return Response.error('Invalid two-step login method.');
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedProvider == null) {
|
||||
if (twoFactorProviders.length === 1) {
|
||||
selectedProvider = twoFactorProviders[0];
|
||||
} else {
|
||||
const options = twoFactorProviders.map((p) => p.name);
|
||||
options.push(new inquirer.Separator());
|
||||
options.push('Cancel');
|
||||
const answer: inquirer.Answers =
|
||||
await inquirer.createPromptModule({ output: process.stderr })({
|
||||
type: 'list',
|
||||
name: 'method',
|
||||
message: 'Two-step login method:',
|
||||
choices: options,
|
||||
});
|
||||
const i = options.indexOf(answer.method);
|
||||
if (i === (options.length - 1)) {
|
||||
return Response.error('Login failed.');
|
||||
}
|
||||
selectedProvider = twoFactorProviders[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (twoFactorToken == null && response.twoFactorProviders.size > 1 &&
|
||||
selectedProvider.type === TwoFactorProviderType.Email) {
|
||||
const emailReq = new TwoFactorEmailRequest(this.authService.email,
|
||||
this.authService.masterPasswordHash);
|
||||
await this.apiService.postTwoFactorEmail(emailReq);
|
||||
}
|
||||
|
||||
if (twoFactorToken == null) {
|
||||
const answer: inquirer.Answers =
|
||||
await inquirer.createPromptModule({ output: process.stderr })({
|
||||
type: 'input',
|
||||
name: 'token',
|
||||
message: 'Two-step login code:',
|
||||
});
|
||||
twoFactorToken = answer.token;
|
||||
if (twoFactorToken == null || twoFactorToken === '') {
|
||||
return Response.badRequest('Code is required.');
|
||||
}
|
||||
}
|
||||
|
||||
response = await this.authService.logInTwoFactor(selectedProvider.type,
|
||||
twoFactorToken, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (response.twoFactor) {
|
||||
return Response.error('Login failed.');
|
||||
}
|
||||
|
||||
await this.syncService.fullSync(true);
|
||||
export class LoginCommand extends BaseLoginCommand {
|
||||
constructor(authService: AuthService, apiService: ApiService,
|
||||
cryptoFunctionService: CryptoFunctionService, syncService: SyncService,
|
||||
i18nService: I18nService) {
|
||||
super(authService, apiService, i18nService);
|
||||
this.validatedParams = async () => {
|
||||
const key = await cryptoFunctionService.randomBytes(64);
|
||||
process.env.BW_SESSION = Utils.fromBufferToB64(key);
|
||||
};
|
||||
this.success = async () => {
|
||||
await syncService.fullSync(true);
|
||||
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' +
|
||||
@ -140,14 +28,7 @@ export class LoginCommand {
|
||||
'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 Response.success(res);
|
||||
} catch (e) {
|
||||
return Response.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private async setNewSessionKey() {
|
||||
const key = await this.cryptoFunctionService.randomBytes(64);
|
||||
process.env.BW_SESSION = Utils.fromBufferToB64(key);
|
||||
return res;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
import * as program from 'commander';
|
||||
|
||||
import { AuthService } from 'jslib/abstractions/auth.service';
|
||||
|
||||
import { Response } from 'jslib/cli/models/response';
|
||||
import { MessageResponse } from 'jslib/cli/models/response/messageResponse';
|
||||
|
||||
export class LogoutCommand {
|
||||
constructor(private authService: AuthService, private logoutCallback: () => Promise<void>) { }
|
||||
|
||||
async run(cmd: program.Command) {
|
||||
await this.logoutCallback();
|
||||
this.authService.logOut(() => { /* Do nothing */ });
|
||||
const res = new MessageResponse('You have logged out.', null);
|
||||
return Response.success(res);
|
||||
}
|
||||
}
|
@ -15,11 +15,11 @@ import { ImportCommand } from './commands/import.command';
|
||||
import { ListCommand } from './commands/list.command';
|
||||
import { LockCommand } from './commands/lock.command';
|
||||
import { LoginCommand } from './commands/login.command';
|
||||
import { LogoutCommand } from './commands/logout.command';
|
||||
import { ShareCommand } from './commands/share.command';
|
||||
import { SyncCommand } from './commands/sync.command';
|
||||
import { UnlockCommand } from './commands/unlock.command';
|
||||
|
||||
import { LogoutCommand } from 'jslib/cli/commands/logout.command';
|
||||
import { UpdateCommand } from 'jslib/cli/commands/update.command';
|
||||
|
||||
import { Response } from 'jslib/cli/models/response';
|
||||
@ -121,7 +121,7 @@ export class Program extends BaseProgram {
|
||||
.action(async (email: string, password: string, cmd: program.Command) => {
|
||||
await this.exitIfAuthed();
|
||||
const command = new LoginCommand(this.main.authService, this.main.apiService,
|
||||
this.main.cryptoFunctionService, this.main.syncService);
|
||||
this.main.cryptoFunctionService, this.main.syncService, this.main.i18nService);
|
||||
const response = await command.run(email, password, cmd);
|
||||
this.processResponse(response);
|
||||
});
|
||||
@ -137,7 +137,8 @@ export class Program extends BaseProgram {
|
||||
})
|
||||
.action(async (cmd) => {
|
||||
await this.exitIfNotAuthed();
|
||||
const command = new LogoutCommand(this.main.authService, async () => await this.main.logout());
|
||||
const command = new LogoutCommand(this.main.authService, this.main.i18nService,
|
||||
async () => await this.main.logout());
|
||||
const response = await command.run(cmd);
|
||||
this.processResponse(response);
|
||||
});
|
||||
@ -557,7 +558,8 @@ export class Program extends BaseProgram {
|
||||
writeLn('', true);
|
||||
})
|
||||
.action(async (cmd) => {
|
||||
const command = new UpdateCommand(this.main.platformUtilsService, 'cli', 'bw');
|
||||
const command = new UpdateCommand(this.main.platformUtilsService, this.main.i18nService,
|
||||
'cli', 'bw', true);
|
||||
const response = await command.run(cmd);
|
||||
this.processResponse(response);
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user