Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@internetarchive/recaptcha-manager

Package Overview
Dependencies
Maintainers
15
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@internetarchive/recaptcha-manager - npm Package Compare versions

Comparing version 0.0.1-alpha.1 to 0.0.1-alpha.2

dist/src/recaptcha-manager copy.d.ts

68

demo/app-root.ts
import { html, css, LitElement } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import { RecaptchaWidget } from '../src/recaptcha-widget';
import {

@@ -12,14 +13,32 @@ RecaptchaManager,

private recaptchaManager?: RecaptchaManagerInterface;
@state() result2?: string;
private recaptchaManager: RecaptchaManagerInterface = new RecaptchaManager({
defaultSiteKey: '6LeTUvYUAAAAAPTvW98MaXyS8c6vxk4-9n8DI1ve',
});
private recaptcha1?: RecaptchaWidget;
private recaptcha2?: RecaptchaWidget;
render() {
return html`
<button @click="${this.loadRecaptcha}">Load Recaptcha</button>
<button @click="${this.executeRecaptcha}">Execute Recaptcha</button>
<slot name="recaptcha"></slot>
<p>
<button @click="${this.loadRecaptcha}">Load Recaptcha</button
><button @click="${this.executeRecaptcha}">Execute Recaptcha</button>
</p>
${this.result
? html`<strong
>Token:<strong><p>${this.result}</p></strong></strong
>`
? html`<p><strong>Token:</strong></p>
<p>${this.result}</p>`
: ''}
<p>
<button @click="${this.loadRecaptcha2}">Load Another Recaptcha</button
><button @click="${this.executeRecaptcha2}">
Execute Another Recaptcha
</button>
</p>
${this.result2
? html`<p><strong>Token 2:</strong></p>
<p>${this.result2}</p>`
: ''}
`;

@@ -29,15 +48,17 @@ }

private async loadRecaptcha() {
this.recaptchaManager = await RecaptchaManager.getRecaptchaManager({
siteKey: '6LeTUvYUAAAAAPTvW98MaXyS8c6vxk4-9n8DI1ve',
this.recaptcha1 = await this.recaptchaManager?.getRecaptchaWidget({
recaptchaParams: {
tabindex: 0,
theme: 'light',
type: 'image',
},
});
const element = document.querySelector('#recaptcha') as HTMLDivElement;
this.recaptchaManager?.setup(element, 0, 'light', 'image');
}
private async executeRecaptcha() {
if (!this.recaptchaManager) {
if (!this.recaptcha1) {
await this.loadRecaptcha();
}
if (!this.recaptchaManager) {
if (!this.recaptcha1) {
console.error('error loading recaptcha');

@@ -47,5 +68,24 @@ return;

this.result = await this.recaptchaManager.execute();
this.result = await this.recaptcha1.execute();
}
private async loadRecaptcha2() {
this.recaptcha2 = await this.recaptchaManager?.getRecaptchaWidget({
siteKey: '6LfDgOgeAAAAAEIzkbGeW4N_yQoN3PxhUYdkxbS6',
});
}
private async executeRecaptcha2() {
if (!this.recaptcha2) {
await this.loadRecaptcha();
}
if (!this.recaptcha2) {
console.error('error loading recaptcha');
return;
}
this.result2 = await this.recaptcha2.execute();
}
static styles = css`

@@ -52,0 +92,0 @@ :host {

import { LitElement } from 'lit';
export declare class AppRoot extends LitElement {
result?: string;
private recaptchaManager?;
result2?: string;
private recaptchaManager;
private recaptcha1?;
private recaptcha2?;
render(): import("lit").TemplateResult<1>;
private loadRecaptcha;
private executeRecaptcha;
private loadRecaptcha2;
private executeRecaptcha2;
static styles: import("lit").CSSResult;
}

@@ -6,12 +6,28 @@ import { __decorate } from "tslib";

let AppRoot = class AppRoot extends LitElement {
constructor() {
super(...arguments);
this.recaptchaManager = new RecaptchaManager({
defaultSiteKey: '6LeTUvYUAAAAAPTvW98MaXyS8c6vxk4-9n8DI1ve',
});
}
render() {
return html `
<button @click="${this.loadRecaptcha}">Load Recaptcha</button>
<button @click="${this.executeRecaptcha}">Execute Recaptcha</button>
<slot name="recaptcha"></slot>
<p>
<button @click="${this.loadRecaptcha}">Load Recaptcha</button
><button @click="${this.executeRecaptcha}">Execute Recaptcha</button>
</p>
${this.result
? html `<strong
>Token:<strong><p>${this.result}</p></strong></strong
>`
? html `<p><strong>Token:</strong></p>
<p>${this.result}</p>`
: ''}
<p>
<button @click="${this.loadRecaptcha2}">Load Another Recaptcha</button
><button @click="${this.executeRecaptcha2}">
Execute Another Recaptcha
</button>
</p>
${this.result2
? html `<p><strong>Token 2:</strong></p>
<p>${this.result2}</p>`
: ''}
`;

@@ -21,18 +37,36 @@ }

var _a;
this.recaptchaManager = await RecaptchaManager.getRecaptchaManager({
siteKey: '6LeTUvYUAAAAAPTvW98MaXyS8c6vxk4-9n8DI1ve',
});
const element = document.querySelector('#recaptcha');
(_a = this.recaptchaManager) === null || _a === void 0 ? void 0 : _a.setup(element, 0, 'light', 'image');
this.recaptcha1 = await ((_a = this.recaptchaManager) === null || _a === void 0 ? void 0 : _a.getRecaptchaWidget({
recaptchaParams: {
tabindex: 0,
theme: 'light',
type: 'image',
},
}));
}
async executeRecaptcha() {
if (!this.recaptchaManager) {
if (!this.recaptcha1) {
await this.loadRecaptcha();
}
if (!this.recaptchaManager) {
if (!this.recaptcha1) {
console.error('error loading recaptcha');
return;
}
this.result = await this.recaptchaManager.execute();
this.result = await this.recaptcha1.execute();
}
async loadRecaptcha2() {
var _a;
this.recaptcha2 = await ((_a = this.recaptchaManager) === null || _a === void 0 ? void 0 : _a.getRecaptchaWidget({
siteKey: '6LfDgOgeAAAAAEIzkbGeW4N_yQoN3PxhUYdkxbS6',
}));
}
async executeRecaptcha2() {
if (!this.recaptcha2) {
await this.loadRecaptcha();
}
if (!this.recaptcha2) {
console.error('error loading recaptcha');
return;
}
this.result2 = await this.recaptcha2.execute();
}
};

@@ -47,2 +81,5 @@ AppRoot.styles = css `

], AppRoot.prototype, "result", void 0);
__decorate([
state()
], AppRoot.prototype, "result2", void 0);
AppRoot = __decorate([

@@ -49,0 +86,0 @@ customElement('app-root')

@@ -1,1 +0,2 @@

export { RecaptchaManager, RecaptchaManagerInterface } from './src/recaptcha-manager';
export { RecaptchaManager, RecaptchaManagerInterface, } from './src/recaptcha-manager';
export { RecaptchaWidget, RecaptchaWidgetInterface, } from './src/recaptcha-widget';

@@ -1,2 +0,3 @@

export { RecaptchaManager } from './src/recaptcha-manager';
export { RecaptchaManager, } from './src/recaptcha-manager';
export { RecaptchaWidget, } from './src/recaptcha-widget';
//# sourceMappingURL=index.js.map
/// <reference types="grecaptcha" />
import { LazyLoaderServiceInterface } from '@internetarchive/lazy-loader-service';
import { RecaptchaWidget } from './recaptcha-widget';
export interface RecaptchaManagerInterface {
execute(): Promise<string>;
setup(container: HTMLElement, tabIndex: number, theme: ReCaptchaV2.Theme, type: ReCaptchaV2.Type): void;
/**
* Load a recaptcha widget for a given site key or the default site key.
*/
getRecaptchaWidget(options?: {
siteKey?: string;
recaptchaParams?: ReCaptchaV2.Parameters;
}): Promise<RecaptchaWidget>;
}
export declare class RecaptchaManager implements RecaptchaManagerInterface {
/**
* This is a convenience initializer that also lazily loads
* the recaptcha library from Google.
*
* @param options
* @returns
*/
static getRecaptchaManager(options: {
siteKey: string;
}): Promise<RecaptchaManagerInterface>;
/**
* Load the Recaptch library from Google.
*
* @param options
* @returns
*/
static loadRecaptchaLibrary(options?: {
private lazyLoader;
private defaultSiteKey?;
private recaptchaCache;
constructor(options: {
defaultSiteKey: string;
lazyLoader?: LazyLoaderServiceInterface;
}): Promise<ReCaptchaV2.ReCaptcha>;
private grecaptchaLibrary;
private siteKey;
constructor(options: {
grecaptchaLibrary: ReCaptchaV2.ReCaptcha;
siteKey: string;
grecaptchaLibrary?: ReCaptchaV2.ReCaptcha;
});
private executionSuccessBlock?;
private executionExpiredBlock?;
private executionErrorBlock?;
private isExecuting;
/** @inheritdoc */
getRecaptchaWidget(options?: {
siteKey?: string;
recaptchaParams?: ReCaptchaV2.Parameters;
}): Promise<RecaptchaWidget>;
/**
* Execute Recaptcha and return a Promise containing the response token.
* Load the Recaptch library from Google.
*
* This is an interesting flow.. we call `execute()` here, but have to wait for the
* response and expiration handlers that we bind during the inital `setup` call.
* For consumers, we want to be able to just call `execute()` and wait for a response.
* To allow this, we assign two callbacks:
* - `executionSuccessBlock`
* - `executionExpiredBlock`
*
* We then call those callbacks from inside `responseHandler` and `expiredHandler` to
* either resolve or reject the Promise.
*
* ie:
*
* try {
* const recaptchaResult = await recaptchaManager.execute();
* console.log('recaptcha token:', recaptchaResult);
* } catch {
* console.error('something happened')
* }
*
* @returns {Promise<string>}
* @memberof RecaptchaManager
* @returns Promise<ReCaptchaV2.ReCaptcha>
*/
execute(): Promise<string>;
private finishExecution;
setup(container: HTMLElement, tabIndex: number, theme: ReCaptchaV2.Theme, type: ReCaptchaV2.Type): void;
private responseHandler;
private expiredHandler;
private errorHandler;
private getRecaptchaLibrary;
/** don't use directly, use `getRecaptchaLibrary()` */
private grecaptchaLibraryCache?;
}
import { LazyLoaderService, } from '@internetarchive/lazy-loader-service';
import { RecaptchaWidget } from './recaptcha-widget';
export class RecaptchaManager {
constructor(options) {
this.isExecuting = false;
this.grecaptchaLibrary = options.grecaptchaLibrary;
this.siteKey = options.siteKey;
var _a;
this.recaptchaCache = {};
this.defaultSiteKey = options.defaultSiteKey;
this.lazyLoader = (_a = options.lazyLoader) !== null && _a !== void 0 ? _a : new LazyLoaderService();
this.grecaptchaLibraryCache = options.grecaptchaLibrary;
}
/**
* This is a convenience initializer that also lazily loads
* the recaptcha library from Google.
*
* @param options
* @returns
*/
static async getRecaptchaManager(options) {
const grecaptchaLibrary = await RecaptchaManager.loadRecaptchaLibrary();
return new RecaptchaManager({
/** @inheritdoc */
async getRecaptchaWidget(options) {
var _a;
const key = (_a = options === null || options === void 0 ? void 0 : options.siteKey) !== null && _a !== void 0 ? _a : this.defaultSiteKey;
if (!key) {
throw new Error('RecaptchaManager requires a site key');
}
const cached = this.recaptchaCache[key];
if (cached)
return cached;
const grecaptchaLibrary = await this.getRecaptchaLibrary();
const recaptcha = new RecaptchaWidget({
siteKey: key,
grecaptchaLibrary,
siteKey: options.siteKey,
});
}, options === null || options === void 0 ? void 0 : options.recaptchaParams);
this.recaptchaCache[key] = recaptcha;
return recaptcha;
}

@@ -25,8 +32,8 @@ /**

*
* @param options
* @returns
* @returns Promise<ReCaptchaV2.ReCaptcha>
*/
static async loadRecaptchaLibrary(options) {
var _a;
const service = (_a = options === null || options === void 0 ? void 0 : options.lazyLoader) !== null && _a !== void 0 ? _a : new LazyLoaderService();
async getRecaptchaLibrary() {
if (this.grecaptchaLibraryCache) {
return this.grecaptchaLibraryCache;
}
return new Promise(resolve => {

@@ -38,5 +45,6 @@ window.grecaptchaLoadedCallback = () => {

}, 10);
this.grecaptchaLibraryCache = window.grecaptcha;
resolve(window.grecaptcha);
};
service.loadScript({
this.lazyLoader.loadScript({
src: 'https://www.google.com/recaptcha/api.js?onload=grecaptchaLoadedCallback&render=explicit',

@@ -46,84 +54,3 @@ });

}
/**
* Execute Recaptcha and return a Promise containing the response token.
*
* This is an interesting flow.. we call `execute()` here, but have to wait for the
* response and expiration handlers that we bind during the inital `setup` call.
* For consumers, we want to be able to just call `execute()` and wait for a response.
* To allow this, we assign two callbacks:
* - `executionSuccessBlock`
* - `executionExpiredBlock`
*
* We then call those callbacks from inside `responseHandler` and `expiredHandler` to
* either resolve or reject the Promise.
*
* ie:
*
* try {
* const recaptchaResult = await recaptchaManager.execute();
* console.log('recaptcha token:', recaptchaResult);
* } catch {
* console.error('something happened')
* }
*
* @returns {Promise<string>}
* @memberof RecaptchaManager
*/
execute() {
if (this.isExecuting) {
this.finishExecution();
}
this.isExecuting = true;
return new Promise((resolve, reject) => {
this.executionSuccessBlock = (token) => {
this.finishExecution();
resolve(token);
};
this.executionExpiredBlock = () => {
this.finishExecution();
reject(new Error('expired'));
};
this.executionErrorBlock = () => {
this.finishExecution();
reject(new Error('error'));
};
this.grecaptchaLibrary.execute();
});
}
finishExecution() {
this.isExecuting = false;
this.grecaptchaLibrary.reset();
}
setup(container, tabIndex, theme, type) {
this.grecaptchaLibrary.render(container, {
callback: this.responseHandler.bind(this),
'expired-callback': this.expiredHandler.bind(this),
'error-callback': this.errorHandler.bind(this),
sitekey: this.siteKey,
tabindex: tabIndex,
theme,
type,
size: 'invisible',
});
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
responseHandler(response) {
if (this.executionSuccessBlock) {
this.executionSuccessBlock(response);
this.executionSuccessBlock = undefined;
}
}
expiredHandler() {
if (this.executionExpiredBlock) {
this.executionExpiredBlock();
this.executionExpiredBlock = undefined;
}
}
errorHandler() {
if (this.executionErrorBlock) {
this.executionErrorBlock();
this.executionErrorBlock = undefined;
}
}
}
//# sourceMappingURL=recaptcha-manager.js.map
"use strict";
describe('YourWebComponent', () => {
});
describe('YourWebComponent', () => { });
//# sourceMappingURL=recaptcha-manager.test.js.map

@@ -1,1 +0,9 @@

export { RecaptchaManager, RecaptchaManagerInterface } from './src/recaptcha-manager';
export {
RecaptchaManager,
RecaptchaManagerInterface,
} from './src/recaptcha-manager';
export {
RecaptchaWidget,
RecaptchaWidgetInterface,
} from './src/recaptcha-widget';

@@ -10,3 +10,3 @@ {

"author": "Internet Archive",
"version": "0.0.1-alpha.1",
"version": "0.0.1-alpha.2",
"main": "dist/index.js",

@@ -13,0 +13,0 @@ "module": "dist/index.js",

@@ -5,42 +5,66 @@ import {

} from '@internetarchive/lazy-loader-service';
import { RecaptchaWidget } from './recaptcha-widget';
export interface RecaptchaManagerInterface {
execute(): Promise<string>;
setup(
container: HTMLElement,
tabIndex: number,
theme: ReCaptchaV2.Theme,
type: ReCaptchaV2.Type
): void;
/**
* Load a recaptcha widget for a given site key or the default site key.
*/
getRecaptchaWidget(options?: {
siteKey?: string;
recaptchaParams?: ReCaptchaV2.Parameters;
}): Promise<RecaptchaWidget>;
}
export class RecaptchaManager implements RecaptchaManagerInterface {
/**
* This is a convenience initializer that also lazily loads
* the recaptcha library from Google.
*
* @param options
* @returns
*/
static async getRecaptchaManager(options: {
siteKey: string;
}): Promise<RecaptchaManagerInterface> {
const grecaptchaLibrary = await RecaptchaManager.loadRecaptchaLibrary();
return new RecaptchaManager({
grecaptchaLibrary,
siteKey: options.siteKey,
});
private lazyLoader: LazyLoaderServiceInterface;
private defaultSiteKey?: string;
private recaptchaCache: Record<string, RecaptchaWidget> = {};
constructor(options: {
defaultSiteKey: string;
lazyLoader?: LazyLoaderServiceInterface;
grecaptchaLibrary?: ReCaptchaV2.ReCaptcha; // allows dependency injection or will be lazy loaded
}) {
this.defaultSiteKey = options.defaultSiteKey;
this.lazyLoader = options.lazyLoader ?? new LazyLoaderService();
this.grecaptchaLibraryCache = options.grecaptchaLibrary;
}
/** @inheritdoc */
async getRecaptchaWidget(options?: {
siteKey?: string;
recaptchaParams?: ReCaptchaV2.Parameters;
}): Promise<RecaptchaWidget> {
const key = options?.siteKey ?? this.defaultSiteKey;
if (!key) {
throw new Error('RecaptchaManager requires a site key');
}
const cached = this.recaptchaCache[key];
if (cached) return cached;
const grecaptchaLibrary = await this.getRecaptchaLibrary();
const recaptcha = new RecaptchaWidget(
{
siteKey: key,
grecaptchaLibrary,
},
options?.recaptchaParams
);
this.recaptchaCache[key] = recaptcha;
return recaptcha;
}
/**
* Load the Recaptch library from Google.
*
* @param options
* @returns
* @returns Promise<ReCaptchaV2.ReCaptcha>
*/
static async loadRecaptchaLibrary(options?: {
lazyLoader?: LazyLoaderServiceInterface;
}): Promise<ReCaptchaV2.ReCaptcha> {
const service = options?.lazyLoader ?? new LazyLoaderService();
private async getRecaptchaLibrary(): Promise<ReCaptchaV2.ReCaptcha> {
if (this.grecaptchaLibraryCache) {
return this.grecaptchaLibraryCache;
}
return new Promise(resolve => {

@@ -52,6 +76,7 @@ (window as any).grecaptchaLoadedCallback = (): void => {

}, 10);
this.grecaptchaLibraryCache = window.grecaptcha;
resolve(window.grecaptcha);
};
service.loadScript({
this.lazyLoader.loadScript({
src: 'https://www.google.com/recaptcha/api.js?onload=grecaptchaLoadedCallback&render=explicit',

@@ -62,116 +87,4 @@ });

private grecaptchaLibrary: ReCaptchaV2.ReCaptcha;
private siteKey: string;
constructor(options: {
grecaptchaLibrary: ReCaptchaV2.ReCaptcha;
siteKey: string;
}) {
this.grecaptchaLibrary = options.grecaptchaLibrary;
this.siteKey = options.siteKey;
}
private executionSuccessBlock?: (token: string) => void;
private executionExpiredBlock?: () => void;
private executionErrorBlock?: () => void;
private isExecuting = false;
/**
* Execute Recaptcha and return a Promise containing the response token.
*
* This is an interesting flow.. we call `execute()` here, but have to wait for the
* response and expiration handlers that we bind during the inital `setup` call.
* For consumers, we want to be able to just call `execute()` and wait for a response.
* To allow this, we assign two callbacks:
* - `executionSuccessBlock`
* - `executionExpiredBlock`
*
* We then call those callbacks from inside `responseHandler` and `expiredHandler` to
* either resolve or reject the Promise.
*
* ie:
*
* try {
* const recaptchaResult = await recaptchaManager.execute();
* console.log('recaptcha token:', recaptchaResult);
* } catch {
* console.error('something happened')
* }
*
* @returns {Promise<string>}
* @memberof RecaptchaManager
*/
execute(): Promise<string> {
if (this.isExecuting) {
this.finishExecution();
}
this.isExecuting = true;
return new Promise((resolve, reject) => {
this.executionSuccessBlock = (token: string): void => {
this.finishExecution();
resolve(token);
};
this.executionExpiredBlock = (): void => {
this.finishExecution();
reject(new Error('expired'));
};
this.executionErrorBlock = (): void => {
this.finishExecution();
reject(new Error('error'));
};
this.grecaptchaLibrary.execute();
});
}
private finishExecution(): void {
this.isExecuting = false;
this.grecaptchaLibrary.reset();
}
setup(
container: HTMLElement,
tabIndex: number,
theme: ReCaptchaV2.Theme,
type: ReCaptchaV2.Type
): void {
this.grecaptchaLibrary.render(container, {
callback: this.responseHandler.bind(this),
'expired-callback': this.expiredHandler.bind(this),
'error-callback': this.errorHandler.bind(this),
sitekey: this.siteKey,
tabindex: tabIndex,
theme,
type,
size: 'invisible',
});
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private responseHandler(response: any): void {
if (this.executionSuccessBlock) {
this.executionSuccessBlock(response);
this.executionSuccessBlock = undefined;
}
}
private expiredHandler(): void {
if (this.executionExpiredBlock) {
this.executionExpiredBlock();
this.executionExpiredBlock = undefined;
}
}
private errorHandler(): void {
if (this.executionErrorBlock) {
this.executionErrorBlock();
this.executionErrorBlock = undefined;
}
}
/** don't use directly, use `getRecaptchaLibrary()` */
private grecaptchaLibraryCache?: ReCaptchaV2.ReCaptcha;
}

@@ -1,3 +0,1 @@

describe('YourWebComponent', () => {
});
describe('YourWebComponent', () => {});

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc