1
0
mirror of https://github.com/bitwarden/browser synced 2026-01-06 10:33:57 +00:00

[Captcha] Failed login attempts (#698)

* [Captcha] Failed login attempts

* Fix logIn.strategy test

* Updated with the stark majority of requested changes

* Fix typo

* Unused import
This commit is contained in:
Vincent Salucci
2022-03-02 19:47:57 -06:00
committed by GitHub
parent adfc2f234d
commit 48a4c27fe7
7 changed files with 124 additions and 47 deletions

View File

@@ -13,7 +13,10 @@ export abstract class AuthService {
logIn: (
credentials: ApiLogInCredentials | PasswordLogInCredentials | SsoLogInCredentials
) => Promise<AuthResult>;
logInTwoFactor: (twoFactor: TokenRequestTwoFactor) => Promise<AuthResult>;
logInTwoFactor: (
twoFactor: TokenRequestTwoFactor,
captchaResponse: string
) => Promise<AuthResult>;
logOut: (callback: () => void) => void;
makePreloginKey: (masterPassword: string, email: string) => Promise<SymmetricCryptoKey>;
authingWithApiKey: () => boolean;

View File

@@ -27,6 +27,7 @@ import { IdentityTwoFactorResponse } from "../../models/response/identityTwoFact
export abstract class LogInStrategy {
protected abstract tokenRequest: ApiTokenRequest | PasswordTokenRequest | SsoTokenRequest;
protected captchaBypassToken: string = null;
constructor(
protected cryptoService: CryptoService,
@@ -44,7 +45,10 @@ export abstract class LogInStrategy {
credentials: ApiLogInCredentials | PasswordLogInCredentials | SsoLogInCredentials
): Promise<AuthResult>;
async logInTwoFactor(twoFactor: TokenRequestTwoFactor): Promise<AuthResult> {
async logInTwoFactor(
twoFactor: TokenRequestTwoFactor,
captchaResponse: string = null
): Promise<AuthResult> {
this.tokenRequest.setTwoFactor(twoFactor);
return this.startLogIn();
}
@@ -152,6 +156,7 @@ export abstract class LogInStrategy {
const result = new AuthResult();
result.twoFactorProviders = response.twoFactorProviders2;
this.twoFactorService.setProviders(response);
this.captchaBypassToken = response.captchaToken ?? null;
return result;
}

View File

@@ -9,9 +9,11 @@ import { StateService } from "../../abstractions/state.service";
import { TokenService } from "../../abstractions/token.service";
import { TwoFactorService } from "../../abstractions/twoFactor.service";
import { HashPurpose } from "../../enums/hashPurpose";
import { AuthResult } from "../../models/domain/authResult";
import { PasswordLogInCredentials } from "../../models/domain/logInCredentials";
import { SymmetricCryptoKey } from "../../models/domain/symmetricCryptoKey";
import { PasswordTokenRequest } from "../../models/request/identityToken/passwordTokenRequest";
import { TokenRequestTwoFactor } from "../../models/request/identityToken/tokenRequest";
import { LogInStrategy } from "./logIn.strategy";
@@ -59,6 +61,14 @@ export class PasswordLogInStrategy extends LogInStrategy {
await this.cryptoService.setKeyHash(this.localHashedPassword);
}
async logInTwoFactor(
twoFactor: TokenRequestTwoFactor,
captchaResponse: string
): Promise<AuthResult> {
this.tokenRequest.captchaResponse = captchaResponse ?? this.captchaBypassToken;
return super.logInTwoFactor(twoFactor);
}
async logIn(credentials: PasswordLogInCredentials) {
const { email, masterPassword, captchaToken, twoFactor } = credentials;

View File

@@ -115,16 +115,19 @@ export class AuthService implements AuthServiceAbstraction {
return result;
}
async logInTwoFactor(twoFactor: TokenRequestTwoFactor): Promise<AuthResult> {
async logInTwoFactor(
twoFactor: TokenRequestTwoFactor,
captchaResponse: string
): Promise<AuthResult> {
if (this.logInStrategy == null) {
throw new Error(this.i18nService.t("sessionTimeout"));
}
try {
const result = await this.logInStrategy.logInTwoFactor(twoFactor);
const result = await this.logInStrategy.logInTwoFactor(twoFactor, captchaResponse);
// Only clear state if 2FA token has been accepted, otherwise we need to be able to try again
if (!result.requiresTwoFactor) {
if (!result.requiresTwoFactor && !result.requiresCaptcha) {
this.clearState();
}
return result;