mirror of
https://github.com/bitwarden/browser.git
synced 2024-09-18 02:41:15 +02:00
two-step login prompts
This commit is contained in:
parent
9ce758e859
commit
e3eea736ed
11
package-lock.json
generated
11
package-lock.json
generated
@ -19,6 +19,12 @@
|
|||||||
"integrity": "sha512-MFFKFv2X4iZy/NFl1m1E8uwE1CR96SGwJjgHma09PLtqOWoj3nqeJHMG+P/EuJGVLvC2I6MdQRQsr4TcRduIow==",
|
"integrity": "sha512-MFFKFv2X4iZy/NFl1m1E8uwE1CR96SGwJjgHma09PLtqOWoj3nqeJHMG+P/EuJGVLvC2I6MdQRQsr4TcRduIow==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/readline-sync": {
|
||||||
|
"version": "1.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/readline-sync/-/readline-sync-1.4.3.tgz",
|
||||||
|
"integrity": "sha512-YP9NVli96E+qQLAF2db+VjnAUEeZcFVg4YnMgr8kpDUFwQBnj31rPLOVHmazbKQhaIkJ9cMHsZhpKdzUeL0KTg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"acorn": {
|
"acorn": {
|
||||||
"version": "5.5.3",
|
"version": "5.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.5.3.tgz",
|
||||||
@ -3186,6 +3192,11 @@
|
|||||||
"set-immediate-shim": "1.0.1"
|
"set-immediate-shim": "1.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"readline-sync": {
|
||||||
|
"version": "1.4.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.9.tgz",
|
||||||
|
"integrity": "sha1-PtqOZfI80qF+YTAbHwADOWr17No="
|
||||||
|
},
|
||||||
"regex-not": {
|
"regex-not": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/commander": "^2.12.2",
|
"@types/commander": "^2.12.2",
|
||||||
"@types/node": "^10.0.8",
|
"@types/node": "^10.0.8",
|
||||||
|
"@types/readline-sync": "^1.4.3",
|
||||||
"clean-webpack-plugin": "^0.1.17",
|
"clean-webpack-plugin": "^0.1.17",
|
||||||
"copy-webpack-plugin": "^4.2.0",
|
"copy-webpack-plugin": "^4.2.0",
|
||||||
"cross-env": "^5.1.4",
|
"cross-env": "^5.1.4",
|
||||||
@ -49,6 +50,7 @@
|
|||||||
"commander": "2.15.1",
|
"commander": "2.15.1",
|
||||||
"node-fetch": "2.1.2",
|
"node-fetch": "2.1.2",
|
||||||
"node-forge": "0.7.1",
|
"node-forge": "0.7.1",
|
||||||
"node-localstorage": "1.3.1"
|
"node-localstorage": "1.3.1",
|
||||||
|
"readline-sync": "1.4.9"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import * as program from 'commander';
|
import * as program from 'commander';
|
||||||
|
import * as readline from 'readline-sync';
|
||||||
|
|
||||||
import { AuthResult } from 'jslib/models/domain/authResult';
|
import { AuthResult } from 'jslib/models/domain/authResult';
|
||||||
|
|
||||||
@ -10,9 +11,57 @@ export class LoginCommand {
|
|||||||
constructor(private authService: AuthService) { }
|
constructor(private authService: AuthService) { }
|
||||||
|
|
||||||
async run(email: string, password: string, cmd: program.Command) {
|
async run(email: string, password: string, cmd: program.Command) {
|
||||||
|
if (email == null || email === '') {
|
||||||
|
email = readline.question('Email Address: ');
|
||||||
|
}
|
||||||
|
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 === '') {
|
||||||
|
password = readline.question('Master Password: ', {
|
||||||
|
hideEchoBack: true,
|
||||||
|
mask: '*',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (password == null || password === '') {
|
||||||
|
return Response.badRequest('Master password is required.');
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await this.authService.logIn(email, password);
|
const response = await this.authService.logIn(email, password);
|
||||||
// TODO: 2FA
|
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 (twoFactorProviders.length === 1) {
|
||||||
|
selectedProvider = twoFactorProviders[0];
|
||||||
|
} else {
|
||||||
|
const options = twoFactorProviders.map((p) => p.name);
|
||||||
|
const i = readline.keyInSelect(options, 'Two-step login method: ', { cancel: 'Cancel' });
|
||||||
|
if (i < 0) {
|
||||||
|
return Response.error('Login failed.');
|
||||||
|
}
|
||||||
|
selectedProvider = twoFactorProviders[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
const twoFactorToken = readline.question('Two-step login token for ' + selectedProvider.name + ': ');
|
||||||
|
if (twoFactorToken == null || twoFactorToken === '') {
|
||||||
|
return Response.badRequest('Token is required.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const twoFactorResponse = await this.authService.logInTwoFactor(selectedProvider.type,
|
||||||
|
twoFactorToken, false);
|
||||||
|
if (twoFactorResponse.twoFactor) {
|
||||||
|
return Response.error('Login failed.');
|
||||||
|
}
|
||||||
|
}
|
||||||
return Response.success();
|
return Response.success();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return Response.error(e);
|
return Response.error(e);
|
||||||
|
@ -46,6 +46,20 @@ export class Program {
|
|||||||
// TODO
|
// TODO
|
||||||
});
|
});
|
||||||
|
|
||||||
|
program
|
||||||
|
.command('lock')
|
||||||
|
.description('Lock the vault and destroy the current session token.')
|
||||||
|
.action((cmd) => {
|
||||||
|
// TODO
|
||||||
|
});
|
||||||
|
|
||||||
|
program
|
||||||
|
.command('unlock <password>')
|
||||||
|
.description('Unlock the vault and obtain a new session token.')
|
||||||
|
.action((cmd) => {
|
||||||
|
// TODO
|
||||||
|
});
|
||||||
|
|
||||||
program
|
program
|
||||||
.command('sync')
|
.command('sync')
|
||||||
.description('Sync user\'s vault from server.')
|
.description('Sync user\'s vault from server.')
|
||||||
@ -117,7 +131,12 @@ export class Program {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private processResponse(response: Response, cmd: program.Command) {
|
private processResponse(response: Response, cmd: program.Command) {
|
||||||
if (response.success) {
|
if (!response.success) {
|
||||||
|
process.stdout.write(chalk.redBright(response.message));
|
||||||
|
process.exit(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (response.data != null) {
|
if (response.data != null) {
|
||||||
if (response.data.object === 'string') {
|
if (response.data.object === 'string') {
|
||||||
process.stdout.write((response.data as StringResponse).data);
|
process.stdout.write((response.data as StringResponse).data);
|
||||||
@ -130,10 +149,6 @@ export class Program {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
process.exit();
|
process.exit();
|
||||||
} else {
|
|
||||||
process.stdout.write(chalk.redBright(response.message));
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private printJson(obj: any, cmd: program.Command) {
|
private printJson(obj: any, cmd: program.Command) {
|
||||||
|
Loading…
Reference in New Issue
Block a user