713 lines
28 KiB
JavaScript
713 lines
28 KiB
JavaScript
|
import * as i0 from '@angular/core';
|
||
|
import { Injectable, EventEmitter, InjectFlags, Directive, Input, Output, forwardRef, Component, ViewChild, NgModule } from '@angular/core';
|
||
|
import { NgControl, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||
|
import { CommonModule } from '@angular/common';
|
||
|
|
||
|
class ScriptService {
|
||
|
constructor(zone) {
|
||
|
this.zone = zone;
|
||
|
this.scriptElemId = "ngx-catpcha-script";
|
||
|
/**
|
||
|
* Name of the global google recaptcha script
|
||
|
*/
|
||
|
this.windowGrecaptcha = "grecaptcha";
|
||
|
/**
|
||
|
* Name of enterpise property in the global google recaptcha script
|
||
|
*/
|
||
|
this.windowGrecaptchaEnterprise = "enterprise";
|
||
|
/**
|
||
|
* Name of the global callback
|
||
|
*/
|
||
|
this.windowOnLoadCallbackProperty = "ngx_captcha_onload_callback";
|
||
|
/**
|
||
|
* Name of the global callback for enterprise
|
||
|
*/
|
||
|
this.windowOnLoadEnterpriseCallbackProperty = "ngx_captcha_onload_enterprise_callback";
|
||
|
this.globalDomain = "recaptcha.net";
|
||
|
this.defaultDomain = "google.com";
|
||
|
this.enterpriseApi = "enterprise.js";
|
||
|
this.defaultApi = "api.js";
|
||
|
}
|
||
|
registerCaptchaScript(config, render, onLoad, language) {
|
||
|
if (this.grecaptchaScriptLoaded(config.useEnterprise)) {
|
||
|
// recaptcha script is already loaded
|
||
|
// just call the callback
|
||
|
if (config.useEnterprise) {
|
||
|
this.zone.run(() => {
|
||
|
onLoad(window[this.windowGrecaptcha][this.windowGrecaptchaEnterprise]);
|
||
|
});
|
||
|
}
|
||
|
else {
|
||
|
this.zone.run(() => {
|
||
|
onLoad(window[this.windowGrecaptcha]);
|
||
|
});
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
// we need to patch the callback through global variable, otherwise callback is not accessible
|
||
|
// note: https://github.com/Enngage/ngx-captcha/issues/2
|
||
|
if (config.useEnterprise) {
|
||
|
window[this.getCallbackName(true)] = ((() => this.zone.run(onLoad.bind(this, window[this.windowGrecaptcha][this.windowGrecaptchaEnterprise]))));
|
||
|
}
|
||
|
else {
|
||
|
window[this.getCallbackName(false)] = ((() => this.zone.run(onLoad.bind(this, window[this.windowGrecaptcha]))));
|
||
|
}
|
||
|
// prepare script elem
|
||
|
const scriptElem = document.createElement("script");
|
||
|
scriptElem.id = this.scriptElemId;
|
||
|
scriptElem.innerHTML = "";
|
||
|
scriptElem.src = this.getCaptchaScriptUrl(config, render, language);
|
||
|
scriptElem.async = true;
|
||
|
scriptElem.defer = true;
|
||
|
// add script to header
|
||
|
document.getElementsByTagName("head")[0].appendChild(scriptElem);
|
||
|
}
|
||
|
cleanup() {
|
||
|
const elem = document.getElementById(this.scriptElemId);
|
||
|
if (elem) {
|
||
|
elem.remove();
|
||
|
}
|
||
|
window[this.getCallbackName()] = undefined;
|
||
|
window[this.windowGrecaptcha] = undefined;
|
||
|
}
|
||
|
/**
|
||
|
* Indicates if google recaptcha script is available and ready to be used
|
||
|
*/
|
||
|
grecaptchaScriptLoaded(useEnterprise) {
|
||
|
if (!window[this.getCallbackName(useEnterprise)] ||
|
||
|
!window[this.windowGrecaptcha]) {
|
||
|
return false;
|
||
|
}
|
||
|
else if (useEnterprise &&
|
||
|
window[this.windowGrecaptcha][this.windowGrecaptchaEnterprise]) {
|
||
|
return true;
|
||
|
// if only enterprise script is loaded we need to check some v3's method
|
||
|
}
|
||
|
else if (window[this.windowGrecaptcha].execute) {
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
/**
|
||
|
* Gets global callback name
|
||
|
* @param useEnterprise Optional flag for enterprise script
|
||
|
* @private
|
||
|
*/
|
||
|
getCallbackName(useEnterprise) {
|
||
|
return useEnterprise
|
||
|
? this.windowOnLoadEnterpriseCallbackProperty
|
||
|
: this.windowOnLoadCallbackProperty;
|
||
|
}
|
||
|
/**
|
||
|
* Gets language param used in script url
|
||
|
*/
|
||
|
getLanguageParam(hl) {
|
||
|
if (!hl) {
|
||
|
return "";
|
||
|
}
|
||
|
return `&hl=${hl}`;
|
||
|
}
|
||
|
/**
|
||
|
* Url to google api script
|
||
|
*/
|
||
|
getCaptchaScriptUrl(config, render, language) {
|
||
|
const domain = config.useGlobalDomain
|
||
|
? this.globalDomain
|
||
|
: this.defaultDomain;
|
||
|
const api = config.useEnterprise ? this.enterpriseApi : this.defaultApi;
|
||
|
const callback = this.getCallbackName(config.useEnterprise);
|
||
|
return `https://www.${domain}/recaptcha/${api}?onload=${callback}&render=${render}${this.getLanguageParam(language)}`;
|
||
|
}
|
||
|
}
|
||
|
/** @nocollapse */ ScriptService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: ScriptService, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
|
||
|
/** @nocollapse */ ScriptService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: ScriptService, providedIn: "root" });
|
||
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: ScriptService, decorators: [{
|
||
|
type: Injectable,
|
||
|
args: [{
|
||
|
providedIn: "root",
|
||
|
}]
|
||
|
}], ctorParameters: function () { return [{ type: i0.NgZone }]; } });
|
||
|
|
||
|
class BaseReCaptchaComponentDirective {
|
||
|
constructor(renderer, zone, injector, scriptService) {
|
||
|
this.renderer = renderer;
|
||
|
this.zone = zone;
|
||
|
this.injector = injector;
|
||
|
this.scriptService = scriptService;
|
||
|
/**
|
||
|
* Prefix of the captcha element
|
||
|
*/
|
||
|
this.captchaElemPrefix = "ngx_captcha_id_";
|
||
|
this.setupCaptcha = true;
|
||
|
/**
|
||
|
* Indicates if global domain 'recaptcha.net' should be used instead of default domain ('google.com')
|
||
|
*/
|
||
|
this.useGlobalDomain = false;
|
||
|
this.useEnterprise = false;
|
||
|
/**
|
||
|
* Type
|
||
|
*/
|
||
|
this.type = "image";
|
||
|
/**
|
||
|
* Tab index
|
||
|
*/
|
||
|
this.tabIndex = 0;
|
||
|
/**
|
||
|
* Called when captcha receives successful response.
|
||
|
* Captcha response token is passed to event.
|
||
|
*/
|
||
|
this.success = new EventEmitter();
|
||
|
/**
|
||
|
* Called when captcha is loaded. Event receives id of the captcha
|
||
|
*/
|
||
|
this.load = new EventEmitter();
|
||
|
/**
|
||
|
* Called when captcha is reset.
|
||
|
*/
|
||
|
this.reset = new EventEmitter();
|
||
|
/**
|
||
|
* Called when captcha is loaded & ready. I.e. when you need to execute captcha on component load.
|
||
|
*/
|
||
|
this.ready = new EventEmitter();
|
||
|
/**
|
||
|
* Error callback
|
||
|
*/
|
||
|
this.error = new EventEmitter();
|
||
|
/**
|
||
|
* Expired callback
|
||
|
*/
|
||
|
this.expire = new EventEmitter();
|
||
|
/**
|
||
|
* Indicates if captcha should be set on load
|
||
|
*/
|
||
|
this.setupAfterLoad = false;
|
||
|
/**
|
||
|
* If enabled, captcha will reset after receiving success response. This is useful
|
||
|
* when invisible captcha need to be resolved multiple times on same page
|
||
|
*/
|
||
|
this.resetCaptchaAfterSuccess = false;
|
||
|
/**
|
||
|
* Required by ControlValueAccessor
|
||
|
*/
|
||
|
this.onChange = (val) => { };
|
||
|
this.onTouched = (val) => { };
|
||
|
/**
|
||
|
* Indicates if captcha is loaded
|
||
|
*/
|
||
|
this.isLoaded = false;
|
||
|
}
|
||
|
ngAfterViewInit() {
|
||
|
this.control = this.injector.get(NgControl, undefined, InjectFlags.Optional)?.control;
|
||
|
}
|
||
|
ngAfterViewChecked() {
|
||
|
if (this.setupCaptcha) {
|
||
|
this.setupCaptcha = false;
|
||
|
this.setupComponent();
|
||
|
}
|
||
|
}
|
||
|
ngOnChanges(changes) {
|
||
|
// cleanup scripts if language changed because they need to be reloaded
|
||
|
if (changes && changes.hl) {
|
||
|
// cleanup scripts when language changes
|
||
|
if (!changes.hl.firstChange &&
|
||
|
changes.hl.currentValue !== changes.hl.previousValue) {
|
||
|
this.scriptService.cleanup();
|
||
|
}
|
||
|
}
|
||
|
if (changes && changes.useGlobalDomain) {
|
||
|
// cleanup scripts when domain changes
|
||
|
if (!changes.useGlobalDomain.firstChange &&
|
||
|
changes.useGlobalDomain.currentValue !==
|
||
|
changes.useGlobalDomain.previousValue) {
|
||
|
this.scriptService.cleanup();
|
||
|
}
|
||
|
}
|
||
|
this.setupCaptcha = true;
|
||
|
}
|
||
|
/**
|
||
|
* Gets captcha response as per reCaptcha docs
|
||
|
*/
|
||
|
getResponse() {
|
||
|
return this.reCaptchaApi.getResponse(this.captchaId);
|
||
|
}
|
||
|
/**
|
||
|
* Gets Id of captcha widget
|
||
|
*/
|
||
|
getCaptchaId() {
|
||
|
return this.captchaId;
|
||
|
}
|
||
|
/**
|
||
|
* Resets captcha
|
||
|
*/
|
||
|
resetCaptcha() {
|
||
|
this.zone.run(() => {
|
||
|
// reset captcha using Google js api
|
||
|
this.reCaptchaApi.reset();
|
||
|
// required due to forms
|
||
|
this.onChange(undefined);
|
||
|
this.onTouched(undefined);
|
||
|
// trigger reset event
|
||
|
this.reset.next();
|
||
|
});
|
||
|
}
|
||
|
/**
|
||
|
* Gets last submitted captcha response
|
||
|
*/
|
||
|
getCurrentResponse() {
|
||
|
return this.currentResponse;
|
||
|
}
|
||
|
/**
|
||
|
* Reload captcha. Useful when properties (i.e. theme) changed and captcha need to reflect them
|
||
|
*/
|
||
|
reloadCaptcha() {
|
||
|
this.setupComponent();
|
||
|
}
|
||
|
ensureCaptchaElem(captchaElemId) {
|
||
|
const captchaElem = document.getElementById(captchaElemId);
|
||
|
if (!captchaElem) {
|
||
|
throw Error(`Captcha element with id '${captchaElemId}' was not found`);
|
||
|
}
|
||
|
// assign captcha alem
|
||
|
this.captchaElem = captchaElem;
|
||
|
}
|
||
|
/**
|
||
|
* Responsible for instantiating captcha element
|
||
|
*/
|
||
|
renderReCaptcha() {
|
||
|
// run outside angular zone due to timeout issues when testing
|
||
|
// details: https://github.com/Enngage/ngx-captcha/issues/26
|
||
|
this.zone.runOutsideAngular(() => {
|
||
|
// to fix reCAPTCHA placeholder element must be an element or id
|
||
|
// https://github.com/Enngage/ngx-captcha/issues/96
|
||
|
setTimeout(() => {
|
||
|
this.captchaId = this.reCaptchaApi.render(this.captchaElemId, this.getCaptchaProperties());
|
||
|
this.ready.next();
|
||
|
}, 0);
|
||
|
});
|
||
|
}
|
||
|
/**
|
||
|
* Called when captcha receives response
|
||
|
* @param callback Callback
|
||
|
*/
|
||
|
handleCallback(callback) {
|
||
|
this.currentResponse = callback;
|
||
|
this.success.next(callback);
|
||
|
this.zone.run(() => {
|
||
|
this.onChange(callback);
|
||
|
this.onTouched(callback);
|
||
|
});
|
||
|
if (this.resetCaptchaAfterSuccess) {
|
||
|
this.resetCaptcha();
|
||
|
}
|
||
|
}
|
||
|
getPseudoUniqueNumber() {
|
||
|
return new Date().getUTCMilliseconds() + Math.floor(Math.random() * 9999);
|
||
|
}
|
||
|
setupComponent() {
|
||
|
// captcha specific setup
|
||
|
this.captchaSpecificSetup();
|
||
|
// create captcha wrapper
|
||
|
this.createAndSetCaptchaElem();
|
||
|
this.scriptService.registerCaptchaScript({
|
||
|
useGlobalDomain: this.useGlobalDomain,
|
||
|
useEnterprise: this.useEnterprise,
|
||
|
}, "explicit", (grecaptcha) => {
|
||
|
this.onloadCallback(grecaptcha);
|
||
|
}, this.hl);
|
||
|
}
|
||
|
/**
|
||
|
* Called when google's recaptcha script is ready
|
||
|
*/
|
||
|
onloadCallback(grecapcha) {
|
||
|
// assign reference to reCaptcha Api once its loaded
|
||
|
this.reCaptchaApi = grecapcha;
|
||
|
if (!this.reCaptchaApi) {
|
||
|
throw Error(`ReCaptcha Api was not initialized correctly`);
|
||
|
}
|
||
|
// loaded flag
|
||
|
this.isLoaded = true;
|
||
|
// fire load event
|
||
|
this.load.next();
|
||
|
// render captcha
|
||
|
this.renderReCaptcha();
|
||
|
// setup component if it was flagged as such
|
||
|
if (this.setupAfterLoad) {
|
||
|
this.setupAfterLoad = false;
|
||
|
this.setupComponent();
|
||
|
}
|
||
|
}
|
||
|
generateNewElemId() {
|
||
|
return this.captchaElemPrefix + this.getPseudoUniqueNumber();
|
||
|
}
|
||
|
createAndSetCaptchaElem() {
|
||
|
// generate new captcha id
|
||
|
this.captchaElemId = this.generateNewElemId();
|
||
|
if (!this.captchaElemId) {
|
||
|
throw Error(`Captcha elem Id is not set`);
|
||
|
}
|
||
|
if (!this.captchaWrapperElem) {
|
||
|
throw Error(`Captcha DOM element is not initialized`);
|
||
|
}
|
||
|
// remove old html
|
||
|
this.captchaWrapperElem.nativeElement.innerHTML = "";
|
||
|
// create new wrapper for captcha
|
||
|
const newElem = this.renderer.createElement("div");
|
||
|
newElem.id = this.captchaElemId;
|
||
|
this.renderer.appendChild(this.captchaWrapperElem.nativeElement, newElem);
|
||
|
// when use captcha in cdk stepper then throwing error Captcha element with id 'ngx_captcha_id_XXXX' not found
|
||
|
// to fix it checking ensureCaptchaElem in timeout so that its check in next call and its able to find element
|
||
|
setTimeout(() => {
|
||
|
// update captcha elem
|
||
|
if (this.captchaElemId) {
|
||
|
this.ensureCaptchaElem(this.captchaElemId);
|
||
|
}
|
||
|
}, 0);
|
||
|
}
|
||
|
/**
|
||
|
* To be aligned with the ControlValueAccessor interface we need to implement this method
|
||
|
* However as we don't want to update the recaptcha, this doesn't need to be implemented
|
||
|
*/
|
||
|
writeValue(obj) { }
|
||
|
/**
|
||
|
* This method helps us tie together recaptcha and our formControl values
|
||
|
*/
|
||
|
registerOnChange(fn) {
|
||
|
this.onChange = fn;
|
||
|
}
|
||
|
/**
|
||
|
* At some point we might be interested whether the user has touched our component
|
||
|
*/
|
||
|
registerOnTouched(fn) {
|
||
|
this.onTouched = fn;
|
||
|
}
|
||
|
/**
|
||
|
* Handles error callback
|
||
|
*/
|
||
|
handleErrorCallback() {
|
||
|
this.zone.run(() => {
|
||
|
this.onChange(undefined);
|
||
|
this.onTouched(undefined);
|
||
|
});
|
||
|
this.error.next();
|
||
|
}
|
||
|
/**
|
||
|
* Handles expired callback
|
||
|
*/
|
||
|
handleExpireCallback() {
|
||
|
this.expire.next();
|
||
|
// reset captcha on expire callback
|
||
|
this.resetCaptcha();
|
||
|
}
|
||
|
}
|
||
|
/** @nocollapse */ BaseReCaptchaComponentDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: BaseReCaptchaComponentDirective, deps: [{ token: i0.Renderer2 }, { token: i0.NgZone }, { token: i0.Injector }, { token: ScriptService }], target: i0.ɵɵFactoryTarget.Directive });
|
||
|
/** @nocollapse */ BaseReCaptchaComponentDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.0.4", type: BaseReCaptchaComponentDirective, inputs: { siteKey: "siteKey", useGlobalDomain: "useGlobalDomain", useEnterprise: "useEnterprise", type: "type", hl: "hl", tabIndex: "tabIndex" }, outputs: { success: "success", load: "load", reset: "reset", ready: "ready", error: "error", expire: "expire" }, usesOnChanges: true, ngImport: i0 });
|
||
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: BaseReCaptchaComponentDirective, decorators: [{
|
||
|
type: Directive
|
||
|
}], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.NgZone }, { type: i0.Injector }, { type: ScriptService }]; }, propDecorators: { siteKey: [{
|
||
|
type: Input
|
||
|
}], useGlobalDomain: [{
|
||
|
type: Input
|
||
|
}], useEnterprise: [{
|
||
|
type: Input
|
||
|
}], type: [{
|
||
|
type: Input
|
||
|
}], hl: [{
|
||
|
type: Input
|
||
|
}], tabIndex: [{
|
||
|
type: Input
|
||
|
}], success: [{
|
||
|
type: Output
|
||
|
}], load: [{
|
||
|
type: Output
|
||
|
}], reset: [{
|
||
|
type: Output
|
||
|
}], ready: [{
|
||
|
type: Output
|
||
|
}], error: [{
|
||
|
type: Output
|
||
|
}], expire: [{
|
||
|
type: Output
|
||
|
}] } });
|
||
|
|
||
|
var ReCaptchaType;
|
||
|
(function (ReCaptchaType) {
|
||
|
ReCaptchaType[ReCaptchaType["InvisibleReCaptcha"] = 0] = "InvisibleReCaptcha";
|
||
|
ReCaptchaType[ReCaptchaType["ReCaptcha2"] = 1] = "ReCaptcha2";
|
||
|
})(ReCaptchaType || (ReCaptchaType = {}));
|
||
|
|
||
|
class InvisibleReCaptchaComponent extends BaseReCaptchaComponentDirective {
|
||
|
constructor(renderer, zone, injector, scriptService) {
|
||
|
super(renderer, zone, injector, scriptService);
|
||
|
this.renderer = renderer;
|
||
|
this.zone = zone;
|
||
|
this.injector = injector;
|
||
|
this.scriptService = scriptService;
|
||
|
/**
|
||
|
* This size representing invisible captcha
|
||
|
*/
|
||
|
this.size = 'invisible';
|
||
|
/**
|
||
|
* Theme
|
||
|
*/
|
||
|
this.theme = 'light';
|
||
|
/**
|
||
|
* Badge
|
||
|
*/
|
||
|
this.badge = 'bottomright';
|
||
|
this.recaptchaType = ReCaptchaType.InvisibleReCaptcha;
|
||
|
}
|
||
|
ngOnChanges(changes) {
|
||
|
super.ngOnChanges(changes);
|
||
|
}
|
||
|
/**
|
||
|
* Programatically invoke the reCAPTCHA check. Used if the invisible reCAPTCHA is on a div instead of a button.
|
||
|
*/
|
||
|
execute() {
|
||
|
// execute captcha
|
||
|
this.zone.runOutsideAngular(() => this.reCaptchaApi.execute(this.captchaId));
|
||
|
}
|
||
|
captchaSpecificSetup() {
|
||
|
}
|
||
|
/**
|
||
|
* Gets reCaptcha properties
|
||
|
*/
|
||
|
getCaptchaProperties() {
|
||
|
return {
|
||
|
'sitekey': this.siteKey,
|
||
|
'callback': (response) => this.zone.run(() => this.handleCallback(response)),
|
||
|
'expired-callback': () => this.zone.run(() => this.handleExpireCallback()),
|
||
|
'error-callback': () => this.zone.run(() => this.handleErrorCallback()),
|
||
|
'badge': this.badge,
|
||
|
'type': this.type,
|
||
|
'tabindex': this.tabIndex,
|
||
|
'size': this.size,
|
||
|
'theme': this.theme
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
/** @nocollapse */ InvisibleReCaptchaComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: InvisibleReCaptchaComponent, deps: [{ token: i0.Renderer2 }, { token: i0.NgZone }, { token: i0.Injector }, { token: ScriptService }], target: i0.ɵɵFactoryTarget.Component });
|
||
|
/** @nocollapse */ InvisibleReCaptchaComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.0.4", type: InvisibleReCaptchaComponent, selector: "ngx-invisible-recaptcha", inputs: { theme: "theme", badge: "badge" }, providers: [
|
||
|
{
|
||
|
provide: NG_VALUE_ACCESSOR,
|
||
|
useExisting: forwardRef((() => InvisibleReCaptchaComponent)),
|
||
|
multi: true,
|
||
|
}
|
||
|
], viewQueries: [{ propertyName: "captchaWrapperElem", first: true, predicate: ["captchaWrapperElem"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: `
|
||
|
<div #captchaWrapperElem></div>`, isInline: true });
|
||
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: InvisibleReCaptchaComponent, decorators: [{
|
||
|
type: Component,
|
||
|
args: [{
|
||
|
selector: 'ngx-invisible-recaptcha',
|
||
|
template: `
|
||
|
<div #captchaWrapperElem></div>`,
|
||
|
providers: [
|
||
|
{
|
||
|
provide: NG_VALUE_ACCESSOR,
|
||
|
useExisting: forwardRef((() => InvisibleReCaptchaComponent)),
|
||
|
multi: true,
|
||
|
}
|
||
|
]
|
||
|
}]
|
||
|
}], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.NgZone }, { type: i0.Injector }, { type: ScriptService }]; }, propDecorators: { theme: [{
|
||
|
type: Input
|
||
|
}], badge: [{
|
||
|
type: Input
|
||
|
}], captchaWrapperElem: [{
|
||
|
type: ViewChild,
|
||
|
args: ['captchaWrapperElem', { static: false }]
|
||
|
}] } });
|
||
|
|
||
|
class ReCaptcha2Component extends BaseReCaptchaComponentDirective {
|
||
|
constructor(renderer, zone, injector, scriptService) {
|
||
|
super(renderer, zone, injector, scriptService);
|
||
|
this.renderer = renderer;
|
||
|
this.zone = zone;
|
||
|
this.injector = injector;
|
||
|
this.scriptService = scriptService;
|
||
|
/**
|
||
|
* Name of the global expire callback
|
||
|
*/
|
||
|
this.windowOnErrorCallbackProperty = 'ngx_captcha_error_callback';
|
||
|
/**
|
||
|
* Name of the global error callback
|
||
|
*/
|
||
|
this.windowOnExpireCallbackProperty = 'ngx_captcha_expire_callback';
|
||
|
/**
|
||
|
* Theme
|
||
|
*/
|
||
|
this.theme = 'light';
|
||
|
/**
|
||
|
* Size
|
||
|
*/
|
||
|
this.size = 'normal';
|
||
|
this.recaptchaType = ReCaptchaType.ReCaptcha2;
|
||
|
}
|
||
|
ngOnChanges(changes) {
|
||
|
super.ngOnChanges(changes);
|
||
|
}
|
||
|
ngOnDestroy() {
|
||
|
window[this.windowOnErrorCallbackProperty] = {};
|
||
|
window[this.windowOnExpireCallbackProperty] = {};
|
||
|
}
|
||
|
captchaSpecificSetup() {
|
||
|
this.registerCallbacks();
|
||
|
}
|
||
|
/**
|
||
|
* Gets reCaptcha properties
|
||
|
*/
|
||
|
getCaptchaProperties() {
|
||
|
return {
|
||
|
'sitekey': this.siteKey,
|
||
|
'callback': (response) => this.zone.run(() => this.handleCallback(response)),
|
||
|
'expired-callback': () => this.zone.run(() => this.handleExpireCallback()),
|
||
|
'error-callback': () => this.zone.run(() => this.handleErrorCallback()),
|
||
|
'theme': this.theme,
|
||
|
'type': this.type,
|
||
|
'size': this.size,
|
||
|
'tabindex': this.tabIndex
|
||
|
};
|
||
|
}
|
||
|
/**
|
||
|
* Registers global callbacks
|
||
|
*/
|
||
|
registerCallbacks() {
|
||
|
window[this.windowOnErrorCallbackProperty] = super.handleErrorCallback.bind(this);
|
||
|
window[this.windowOnExpireCallbackProperty] = super.handleExpireCallback.bind(this);
|
||
|
}
|
||
|
}
|
||
|
/** @nocollapse */ ReCaptcha2Component.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: ReCaptcha2Component, deps: [{ token: i0.Renderer2 }, { token: i0.NgZone }, { token: i0.Injector }, { token: ScriptService }], target: i0.ɵɵFactoryTarget.Component });
|
||
|
/** @nocollapse */ ReCaptcha2Component.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.0.4", type: ReCaptcha2Component, selector: "ngx-recaptcha2", inputs: { theme: "theme", size: "size" }, providers: [
|
||
|
{
|
||
|
provide: NG_VALUE_ACCESSOR,
|
||
|
useExisting: forwardRef((() => ReCaptcha2Component)),
|
||
|
multi: true,
|
||
|
}
|
||
|
], viewQueries: [{ propertyName: "captchaWrapperElem", first: true, predicate: ["captchaWrapperElem"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: `
|
||
|
<div #captchaWrapperElem></div>`, isInline: true });
|
||
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: ReCaptcha2Component, decorators: [{
|
||
|
type: Component,
|
||
|
args: [{
|
||
|
selector: 'ngx-recaptcha2',
|
||
|
template: `
|
||
|
<div #captchaWrapperElem></div>`,
|
||
|
providers: [
|
||
|
{
|
||
|
provide: NG_VALUE_ACCESSOR,
|
||
|
useExisting: forwardRef((() => ReCaptcha2Component)),
|
||
|
multi: true,
|
||
|
}
|
||
|
]
|
||
|
}]
|
||
|
}], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.NgZone }, { type: i0.Injector }, { type: ScriptService }]; }, propDecorators: { theme: [{
|
||
|
type: Input
|
||
|
}], size: [{
|
||
|
type: Input
|
||
|
}], captchaWrapperElem: [{
|
||
|
type: ViewChild,
|
||
|
args: ['captchaWrapperElem', { static: false }]
|
||
|
}] } });
|
||
|
|
||
|
class ReCaptchaV3Service {
|
||
|
constructor(scriptService, zone) {
|
||
|
this.scriptService = scriptService;
|
||
|
this.zone = zone;
|
||
|
}
|
||
|
/**
|
||
|
* Executes reCaptcha v3/Enterprise with given action and passes token via callback. You need to verify
|
||
|
* this callback in your backend to get meaningful results.
|
||
|
*
|
||
|
* For more information see https://developers.google.com/recaptcha/docs/v3
|
||
|
* For enterprise see https://cloud.google.com/recaptcha-enterprise/docs
|
||
|
*
|
||
|
* @param siteKey Site key found in your google admin panel
|
||
|
* @param action Action to log
|
||
|
* @param callback Callback function to to handle token
|
||
|
* @param config Optional configuration like useGlobalDomain to be provided
|
||
|
* @param errorCallback Optional Callback function to handle errors
|
||
|
*/
|
||
|
execute(siteKey, action, callback, config, errorCallback) {
|
||
|
this.executeAsPromise(siteKey, action, config)
|
||
|
.then(callback)
|
||
|
.catch((error) => errorCallback ? errorCallback(error) : console.error(error));
|
||
|
}
|
||
|
/**
|
||
|
* Executes reCaptcha v3/Enterprise with given action and returns token via Promise. You need to verify
|
||
|
* this token in your backend to get meaningful results.
|
||
|
*
|
||
|
* For more information see https://developers.google.com/recaptcha/docs/v3
|
||
|
* For enterprise see https://cloud.google.com/recaptcha-enterprise/docs
|
||
|
*
|
||
|
* @param siteKey Site key found in your google admin panel
|
||
|
* @param action Action to log
|
||
|
* @param config Optional configuration like useGlobalDomain to be provided
|
||
|
*/
|
||
|
executeAsPromise(siteKey, action, config) {
|
||
|
return new Promise((resolve, reject) => {
|
||
|
const configuration = config || {};
|
||
|
const onRegister = (grecaptcha) => {
|
||
|
this.zone.runOutsideAngular(() => {
|
||
|
try {
|
||
|
grecaptcha
|
||
|
.execute(siteKey, { action })
|
||
|
.then((token) => this.zone.run(() => resolve(token)));
|
||
|
}
|
||
|
catch (error) {
|
||
|
reject(error);
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
this.scriptService.registerCaptchaScript(configuration, siteKey, onRegister);
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
/** @nocollapse */ ReCaptchaV3Service.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: ReCaptchaV3Service, deps: [{ token: ScriptService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
|
||
|
/** @nocollapse */ ReCaptchaV3Service.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: ReCaptchaV3Service, providedIn: "root" });
|
||
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: ReCaptchaV3Service, decorators: [{
|
||
|
type: Injectable,
|
||
|
args: [{
|
||
|
providedIn: "root",
|
||
|
}]
|
||
|
}], ctorParameters: function () { return [{ type: ScriptService }, { type: i0.NgZone }]; } });
|
||
|
|
||
|
class NgxCaptchaModule {
|
||
|
}
|
||
|
/** @nocollapse */ NgxCaptchaModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: NgxCaptchaModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
||
|
/** @nocollapse */ NgxCaptchaModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.0.4", ngImport: i0, type: NgxCaptchaModule, declarations: [ReCaptcha2Component,
|
||
|
InvisibleReCaptchaComponent], imports: [CommonModule], exports: [ReCaptcha2Component,
|
||
|
InvisibleReCaptchaComponent] });
|
||
|
/** @nocollapse */ NgxCaptchaModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: NgxCaptchaModule, providers: [
|
||
|
ScriptService,
|
||
|
ReCaptchaV3Service
|
||
|
], imports: [CommonModule] });
|
||
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: NgxCaptchaModule, decorators: [{
|
||
|
type: NgModule,
|
||
|
args: [{
|
||
|
imports: [
|
||
|
CommonModule
|
||
|
],
|
||
|
declarations: [
|
||
|
ReCaptcha2Component,
|
||
|
InvisibleReCaptchaComponent
|
||
|
],
|
||
|
providers: [
|
||
|
ScriptService,
|
||
|
ReCaptchaV3Service
|
||
|
],
|
||
|
exports: [
|
||
|
ReCaptcha2Component,
|
||
|
InvisibleReCaptchaComponent
|
||
|
]
|
||
|
}]
|
||
|
}] });
|
||
|
|
||
|
/*
|
||
|
* Public API
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* Generated bundle index. Do not edit.
|
||
|
*/
|
||
|
|
||
|
export { BaseReCaptchaComponentDirective, InvisibleReCaptchaComponent, NgxCaptchaModule, ReCaptcha2Component, ReCaptchaType, ReCaptchaV3Service, ScriptService };
|
||
|
//# sourceMappingURL=ngx-captcha.mjs.map
|