1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-16 08:13:42 +00:00

chore(captcha): [PM-15162] Remove handling of captcha enforcement and bypass token

* Removed captcha references.

* Removed connectors from webpack

* Fixed extra parameter.

* Resolve merge conflicts.

* Fixed extra argument.

* Fixed failing tests.

* Fixed failing test.

* Accessibility cookie cleanup

* Cleaned up accessibility component.

* Deleted old registration endpoint

* Remove unused register request object.

* Fixed merge error that changed font family.

* Fixed formatting from merge.

* Linting
This commit is contained in:
Todd Martin
2025-05-09 10:44:11 -04:00
committed by GitHub
parent 625256b08e
commit 4191bb9533
59 changed files with 56 additions and 977 deletions

View File

@@ -47,10 +47,9 @@ export abstract class AccountApiService {
* @param request - The request object containing the user's email verification token,
* the email, hashed MP, newly created user key, and new asymmetric user key pair along
* with the KDF information used during the process.
* @returns A promise that resolves to a string captcha bypass token when the
* registration process is successfully completed.
* @returns A promise that resolves when the registration process is successfully completed.
*/
abstract registerFinish(request: RegisterFinishRequest): Promise<string>;
abstract registerFinish(request: RegisterFinishRequest): Promise<void>;
/**
* Sets the [dbo].[User].[VerifyDevices] flag to true or false.

View File

@@ -1,39 +0,0 @@
import { I18nService } from "../platform/abstractions/i18n.service";
import { IFrameComponent } from "./iframe-component";
// TODO: PM-15162 - captcha is deprecated as part of UI refresh work
export class CaptchaIFrame extends IFrameComponent {
constructor(
win: Window,
webVaultUrl: string,
private i18nService: I18nService,
successCallback: (message: string) => any,
errorCallback: (message: string) => any,
infoCallback: (message: string) => any,
) {
super(
win,
webVaultUrl,
"captcha-connector.html",
"hcaptcha_iframe",
successCallback,
errorCallback,
(message: string) => {
const parsedMessage = JSON.parse(message);
if (typeof parsedMessage !== "string") {
this.iframe.height = parsedMessage.height.toString();
this.iframe.width = parsedMessage.width.toString();
} else {
infoCallback(parsedMessage);
}
},
);
}
init(siteKey: string): void {
super.initComponent(
this.createParams({ siteKey: siteKey, locale: this.i18nService.translationLocale }, 1),
);
}
}

View File

@@ -1,96 +0,0 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
export abstract class IFrameComponent {
iframe: HTMLIFrameElement;
private connectorLink: HTMLAnchorElement;
private parseFunction = this.parseMessage.bind(this);
constructor(
private win: Window,
protected webVaultUrl: string,
private path: string,
private iframeId: string,
public successCallback?: (message: string) => any,
public errorCallback?: (message: string) => any,
public infoCallback?: (message: string) => any,
) {
this.connectorLink = win.document.createElement("a");
}
stop() {
this.sendMessage("stop");
}
start() {
this.sendMessage("start");
}
sendMessage(message: any) {
if (!this.iframe || !this.iframe.src || !this.iframe.contentWindow) {
return;
}
this.iframe.contentWindow.postMessage(message, this.iframe.src);
}
base64Encode(str: string): string {
return btoa(
encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (match, p1) => {
return String.fromCharCode(("0x" + p1) as any);
}),
);
}
cleanup() {
this.win.removeEventListener("message", this.parseFunction, false);
}
protected createParams(data: any, version: number) {
return new URLSearchParams({
data: this.base64Encode(JSON.stringify(data)),
parent: encodeURIComponent(this.win.document.location.href),
v: version.toString(),
});
}
protected initComponent(params: URLSearchParams): void {
this.connectorLink.href = `${this.webVaultUrl}/${this.path}?${params}`;
this.iframe = this.win.document.getElementById(this.iframeId) as HTMLIFrameElement;
this.iframe.src = this.connectorLink.href;
this.win.addEventListener("message", this.parseFunction, false);
}
private parseMessage(event: MessageEvent) {
if (!this.validMessage(event)) {
return;
}
const parts: string[] = event.data.split("|");
if (parts[0] === "success" && this.successCallback) {
this.successCallback(parts[1]);
} else if (parts[0] === "error" && this.errorCallback) {
this.errorCallback(parts[1]);
} else if (parts[0] === "info" && this.infoCallback) {
this.infoCallback(parts[1]);
}
}
private validMessage(event: MessageEvent) {
if (
event.origin == null ||
event.origin === "" ||
event.origin !== (this.connectorLink as any).origin ||
event.data == null ||
typeof event.data !== "string"
) {
return false;
}
return (
event.data.indexOf("success|") === 0 ||
event.data.indexOf("error|") === 0 ||
event.data.indexOf("info|") === 0
);
}
}

View File

@@ -1,12 +1,10 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { Utils } from "../../../platform/misc/utils";
import { UserId } from "../../../types/guid";
import { TwoFactorProviderType } from "../../enums/two-factor-provider-type";
export class AuthResult {
userId: UserId;
captchaSiteKey = "";
// TODO: PM-3287 - Remove this after 3 releases of backwards compatibility. - Target release 2023.12 for removal
/**
* @deprecated
@@ -21,10 +19,6 @@ export class AuthResult {
requiresEncryptionKeyMigration: boolean;
requiresDeviceVerification: boolean;
get requiresCaptcha() {
return !Utils.isNullOrWhitespace(this.captchaSiteKey);
}
get requiresTwoFactor() {
return this.twoFactorProviders != null;
}

View File

@@ -1,5 +0,0 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
export abstract class CaptchaProtectedRequest {
captchaResponse: string = null;
}

View File

@@ -1,16 +1,14 @@
import { ClientType } from "../../../../enums";
import { Utils } from "../../../../platform/misc/utils";
import { CaptchaProtectedRequest } from "../captcha-protected.request";
import { DeviceRequest } from "./device.request";
import { TokenTwoFactorRequest } from "./token-two-factor.request";
import { TokenRequest } from "./token.request";
export class PasswordTokenRequest extends TokenRequest implements CaptchaProtectedRequest {
export class PasswordTokenRequest extends TokenRequest {
constructor(
public email: string,
public masterPasswordHash: string,
public captchaResponse: string,
protected twoFactor: TokenTwoFactorRequest,
device?: DeviceRequest,
public newDeviceOtp?: string,
@@ -25,10 +23,6 @@ export class PasswordTokenRequest extends TokenRequest implements CaptchaProtect
obj.username = this.email;
obj.password = this.masterPasswordHash;
if (this.captchaResponse != null) {
obj.captchaResponse = this.captchaResponse;
}
if (this.newDeviceOtp) {
obj.newDeviceOtp = this.newDeviceOtp;
}

View File

@@ -1,3 +0,0 @@
export interface ICaptchaProtectedResponse {
captchaBypassToken: string;
}

View File

@@ -1,10 +0,0 @@
import { BaseResponse } from "../../../models/response/base.response";
export class IdentityCaptchaResponse extends BaseResponse {
siteKey: string;
constructor(response: any) {
super(response);
this.siteKey = this.getResponseProperty("HCaptcha_SiteKey");
}
}

View File

@@ -2,12 +2,9 @@ import { BaseResponse } from "@bitwarden/common/models/response/base.response";
export class IdentityDeviceVerificationResponse extends BaseResponse {
deviceVerified: boolean;
captchaToken: string;
constructor(response: any) {
super(response);
this.deviceVerified = this.getResponseProperty("DeviceVerified") ?? false;
this.captchaToken = this.getResponseProperty("CaptchaBypassToken");
}
}

View File

@@ -8,14 +8,12 @@ export class IdentityTwoFactorResponse extends BaseResponse {
twoFactorProviders: TwoFactorProviderType[];
// a map of two-factor providers to necessary data for completion
twoFactorProviders2: Record<TwoFactorProviderType, Record<string, string>>;
captchaToken: string;
ssoEmail2faSessionToken: string;
email?: string;
masterPasswordPolicy?: MasterPasswordPolicyResponse;
constructor(response: any) {
super(response);
this.captchaToken = this.getResponseProperty("CaptchaBypassToken");
this.twoFactorProviders = this.getResponseProperty("TwoFactorProviders");
this.twoFactorProviders2 = this.getResponseProperty("TwoFactorProviders2");
this.masterPasswordPolicy = new MasterPasswordPolicyResponse(

View File

@@ -1,12 +0,0 @@
import { BaseResponse } from "../../../models/response/base.response";
import { ICaptchaProtectedResponse } from "./captcha-protected.response";
export class RegisterResponse extends BaseResponse implements ICaptchaProtectedResponse {
captchaBypassToken: string;
constructor(response: any) {
super(response);
this.captchaBypassToken = this.getResponseProperty("CaptchaBypassToken");
}
}

View File

@@ -84,7 +84,7 @@ export class AccountApiServiceImplementation implements AccountApiService {
}
}
async registerFinish(request: RegisterFinishRequest): Promise<string> {
async registerFinish(request: RegisterFinishRequest): Promise<void> {
const env = await firstValueFrom(this.environmentService.environment$);
try {