1
0
mirror of https://github.com/bitwarden/browser synced 2026-01-07 02:53:28 +00:00

Feature/use hcaptcha if bot (#430)

* Handle hcaptch required identity response

* Refactor iframe component for captcha and webauthn

* Send captcha token to server

* Add captcha callback

* Clear captcha state

* Remove captcha storage

* linter fixes

* Rename iframe components to include IFrame

* Remove callback in favor of extenting submit

* Limit publickey credentials access

* Use captcha bypass token to bypass captcha for twofactor auth flows

* Linter fixes

* Set iframe version in components
This commit is contained in:
Matt Gibson
2021-07-21 07:55:26 -05:00
committed by GitHub
parent 00acbce556
commit 1006f50ef3
13 changed files with 143 additions and 47 deletions

View File

@@ -160,6 +160,7 @@ import { ChallengeResponse } from '../models/response/twoFactorWebAuthnResponse'
import { TwoFactorYubiKeyResponse } from '../models/response/twoFactorYubiKeyResponse';
import { UserKeyResponse } from '../models/response/userKeyResponse';
import { IdentityCaptchaResponse } from '../models/response/identityCaptchaResponse';
import { SendAccessView } from '../models/view/sendAccessView';
export class ApiService implements ApiServiceAbstraction {
@@ -215,7 +216,7 @@ export class ApiService implements ApiServiceAbstraction {
// Auth APIs
async postIdentityToken(request: TokenRequest): Promise<IdentityTokenResponse | IdentityTwoFactorResponse> {
async postIdentityToken(request: TokenRequest): Promise<IdentityTokenResponse | IdentityTwoFactorResponse | IdentityCaptchaResponse> {
const headers = new Headers({
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
'Accept': 'application/json',
@@ -245,6 +246,9 @@ export class ApiService implements ApiServiceAbstraction {
Object.keys(responseJson.TwoFactorProviders2).length) {
await this.tokenService.clearTwoFactorToken(request.email);
return new IdentityTwoFactorResponse(responseJson);
} else if (response.status === 400 && responseJson.HCaptcha_SiteKey &&
Object.keys(responseJson.HCaptcha_SiteKey).length) {
return new IdentityCaptchaResponse(responseJson);
}
}

View File

@@ -87,6 +87,7 @@ export class AuthService implements AuthServiceAbstraction {
clientSecret: string;
twoFactorProvidersData: Map<TwoFactorProviderType, { [key: string]: string; }>;
selectedTwoFactorProviderType: TwoFactorProviderType = null;
captchaToken: string;
private key: SymmetricCryptoKey;
@@ -120,14 +121,14 @@ export class AuthService implements AuthServiceAbstraction {
TwoFactorProviders[TwoFactorProviderType.Yubikey].description = this.i18nService.t('yubiKeyDesc');
}
async logIn(email: string, masterPassword: string): Promise<AuthResult> {
async logIn(email: string, masterPassword: string, captchaToken?: string): Promise<AuthResult> {
this.selectedTwoFactorProviderType = null;
const key = await this.makePreloginKey(masterPassword, email);
const hashedPassword = await this.cryptoService.hashPassword(masterPassword, key);
const localHashedPassword = await this.cryptoService.hashPassword(masterPassword, key,
HashPurpose.LocalAuthorization);
return await this.logInHelper(email, hashedPassword, localHashedPassword, null, null, null, null, null,
key, null, null, null);
key, null, null, null, captchaToken);
}
async logInSso(code: string, codeVerifier: string, redirectUrl: string): Promise<AuthResult> {
@@ -146,7 +147,7 @@ export class AuthService implements AuthServiceAbstraction {
remember?: boolean): Promise<AuthResult> {
return await this.logInHelper(this.email, this.masterPasswordHash, this.localMasterPasswordHash, this.code,
this.codeVerifier, this.ssoRedirectUrl, this.clientId, this.clientSecret, this.key, twoFactorProvider,
twoFactorToken, remember);
twoFactorToken, remember, this.captchaToken);
}
async logInComplete(email: string, masterPassword: string, twoFactorProvider: TwoFactorProviderType,
@@ -272,7 +273,7 @@ export class AuthService implements AuthServiceAbstraction {
private async logInHelper(email: string, hashedPassword: string, localHashedPassword: string, code: string,
codeVerifier: string, redirectUrl: string, clientId: string, clientSecret: string, key: SymmetricCryptoKey,
twoFactorProvider?: TwoFactorProviderType, twoFactorToken?: string, remember?: boolean): Promise<AuthResult> {
twoFactorProvider?: TwoFactorProviderType, twoFactorToken?: string, remember?: boolean, captchaToken?: string): Promise<AuthResult> {
const storedTwoFactorToken = await this.tokenService.getTwoFactorToken(email);
const appId = await this.appIdService.getAppId();
const deviceRequest = new DeviceRequest(appId, this.platformUtilsService);
@@ -300,24 +301,27 @@ export class AuthService implements AuthServiceAbstraction {
let request: TokenRequest;
if (twoFactorToken != null && twoFactorProvider != null) {
request = new TokenRequest(emailPassword, codeCodeVerifier, clientIdClientSecret, twoFactorProvider,
twoFactorToken, remember, deviceRequest);
twoFactorToken, remember, captchaToken, deviceRequest);
} else if (storedTwoFactorToken != null) {
request = new TokenRequest(emailPassword, codeCodeVerifier, clientIdClientSecret, TwoFactorProviderType.Remember,
storedTwoFactorToken, false, deviceRequest);
request = new TokenRequest(emailPassword, codeCodeVerifier, clientIdClientSecret,
TwoFactorProviderType.Remember, storedTwoFactorToken, false, captchaToken, deviceRequest);
} else {
request = new TokenRequest(emailPassword, codeCodeVerifier, clientIdClientSecret, null,
null, false, deviceRequest);
null, false, captchaToken, deviceRequest);
}
const response = await this.apiService.postIdentityToken(request);
this.clearState();
const result = new AuthResult();
result.twoFactor = !(response as any).accessToken;
result.captchaSiteKey = (response as any).siteKey;
if (!!result.captchaSiteKey) {
return result;
}
result.twoFactor = !!(response as any).twoFactorProviders2;
if (result.twoFactor) {
// two factor required
const twoFactorResponse = response as IdentityTwoFactorResponse;
this.email = email;
this.masterPasswordHash = hashedPassword;
this.localMasterPasswordHash = localHashedPassword;
@@ -327,8 +331,10 @@ export class AuthService implements AuthServiceAbstraction {
this.clientId = clientId;
this.clientSecret = clientSecret;
this.key = this.setCryptoKeys ? key : null;
const twoFactorResponse = response as IdentityTwoFactorResponse;
this.twoFactorProvidersData = twoFactorResponse.twoFactorProviders2;
result.twoFactorProviders = twoFactorResponse.twoFactorProviders2;
this.captchaToken = twoFactorResponse.captchaToken;
return result;
}