UNPKG

veritatisdoloremque

Version:
161 lines (140 loc) 4.4 kB
/** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { AuthErrorCode } from '../../core/errors'; import { _assert } from '../../core/util/assert'; import { AuthInternal } from '../../model/auth'; import { Parameters, Recaptcha } from './recaptcha'; export const _SOLVE_TIME_MS = 500; export const _EXPIRATION_TIME_MS = 60_000; export const _WIDGET_ID_START = 1_000_000_000_000; export interface Widget { getResponse: () => string | null; delete: () => void; execute: () => void; } export class MockReCaptcha implements Recaptcha { private counter = _WIDGET_ID_START; _widgets = new Map<number, Widget>(); constructor(private readonly auth: AuthInternal) {} render(container: string | HTMLElement, parameters?: Parameters): number { const id = this.counter; this._widgets.set( id, new MockWidget(container, this.auth.name, parameters || {}) ); this.counter++; return id; } reset(optWidgetId?: number): void { const id = optWidgetId || _WIDGET_ID_START; void this._widgets.get(id)?.delete(); this._widgets.delete(id); } getResponse(optWidgetId?: number): string { const id = optWidgetId || _WIDGET_ID_START; return this._widgets.get(id)?.getResponse() || ''; } async execute(optWidgetId?: number | string): Promise<string> { const id: number = (optWidgetId as number) || _WIDGET_ID_START; void this._widgets.get(id)?.execute(); return ''; } } export class MockWidget { private readonly container: HTMLElement; private readonly isVisible: boolean; private timerId: number | null = null; private deleted = false; private responseToken: string | null = null; private readonly clickHandler = (): void => { this.execute(); }; constructor( containerOrId: string | HTMLElement, appName: string, private readonly params: Parameters ) { const container = typeof containerOrId === 'string' ? document.getElementById(containerOrId) : containerOrId; _assert(container, AuthErrorCode.ARGUMENT_ERROR, { appName }); this.container = container; this.isVisible = this.params.size !== 'invisible'; if (this.isVisible) { this.execute(); } else { this.container.addEventListener('click', this.clickHandler); } } getResponse(): string | null { this.checkIfDeleted(); return this.responseToken; } delete(): void { this.checkIfDeleted(); this.deleted = true; if (this.timerId) { clearTimeout(this.timerId); this.timerId = null; } this.container.removeEventListener('click', this.clickHandler); } execute(): void { this.checkIfDeleted(); if (this.timerId) { return; } this.timerId = window.setTimeout(() => { this.responseToken = generateRandomAlphaNumericString(50); const { callback, 'expired-callback': expiredCallback } = this.params; if (callback) { try { callback(this.responseToken); } catch (e) {} } this.timerId = window.setTimeout(() => { this.timerId = null; this.responseToken = null; if (expiredCallback) { try { expiredCallback(); } catch (e) {} } if (this.isVisible) { this.execute(); } }, _EXPIRATION_TIME_MS); }, _SOLVE_TIME_MS); } private checkIfDeleted(): void { if (this.deleted) { throw new Error('reCAPTCHA mock was already deleted!'); } } } function generateRandomAlphaNumericString(len: number): string { const chars = []; const allowedChars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; for (let i = 0; i < len; i++) { chars.push( allowedChars.charAt(Math.floor(Math.random() * allowedChars.length)) ); } return chars.join(''); }