ngx-captcha-ssr
Version:
Dynamic captcha (Google reCaptcha) implementation for Angular
134 lines • 18 kB
JavaScript
import { isPlatformBrowser } from "@angular/common";
import { Inject, Injectable, NgZone, PLATFORM_ID } from "@angular/core";
import * as i0 from "@angular/core";
export class ScriptService {
constructor(zone, platformId) {
this.zone = zone;
this.platformId = platformId;
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 (isPlatformBrowser(this.platformId)) {
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 }, { token: PLATFORM_ID }], 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 }, { type: Object, decorators: [{
type: Inject,
args: [PLATFORM_ID]
}] }]; } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2NyaXB0LnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3NlcnZpY2VzL3NjcmlwdC5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ3BELE9BQU8sRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxXQUFXLEVBQUUsTUFBTSxlQUFlLENBQUM7O0FBTXhFLE1BQU0sT0FBTyxhQUFhO0lBaUN4QixZQUFzQixJQUFZLEVBQStCLFVBQWtCO1FBQTdELFNBQUksR0FBSixJQUFJLENBQVE7UUFBK0IsZUFBVSxHQUFWLFVBQVUsQ0FBUTtRQWhDbEUsaUJBQVksR0FBVyxvQkFBb0IsQ0FBQztRQUU3RDs7V0FFRztRQUNnQixxQkFBZ0IsR0FBRyxZQUFZLENBQUM7UUFFbkQ7O1dBRUc7UUFDZ0IsK0JBQTBCLEdBQUcsWUFBWSxDQUFDO1FBRTdEOztXQUVHO1FBQ2dCLGlDQUE0QixHQUM3Qyw2QkFBNkIsQ0FBQztRQUVoQzs7V0FFRztRQUNnQiwyQ0FBc0MsR0FDdkQsd0NBQXdDLENBQUM7UUFFeEIsaUJBQVksR0FBVyxlQUFlLENBQUM7UUFFdkMsa0JBQWEsR0FBVyxZQUFZLENBQUM7UUFFckMsa0JBQWEsR0FBVyxlQUFlLENBQUM7UUFFeEMsZUFBVSxHQUFXLFFBQVEsQ0FBQztJQUVzQyxDQUFDO0lBRXhGLHFCQUFxQixDQUNuQixNQUE4QixFQUM5QixNQUFjLEVBQ2QsTUFBaUMsRUFDakMsUUFBaUI7UUFFakIsSUFBSSxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEVBQUU7WUFDdEMsSUFBSSxJQUFJLENBQUMsc0JBQXNCLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxFQUFFO2dCQUNyRCxxQ0FBcUM7Z0JBQ3JDLHlCQUF5QjtnQkFDekIsSUFBSSxNQUFNLENBQUMsYUFBYSxFQUFFO29C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OzJCQUFDLFdBQVciLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBpc1BsYXRmb3JtQnJvd3NlciB9IGZyb20gXCJAYW5ndWxhci9jb21tb25cIjtcclxuaW1wb3J0IHsgSW5qZWN0LCBJbmplY3RhYmxlLCBOZ1pvbmUsIFBMQVRGT1JNX0lEIH0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcclxuaW1wb3J0IHsgUmVjYXB0Y2hhQ29uZmlndXJhdGlvbiB9IGZyb20gXCIuLi9tb2RlbHMvcmVjYXB0Y2hhLWNvbmZpZ3VyYXRpb25cIjtcclxuXHJcbkBJbmplY3RhYmxlKHtcclxuICBwcm92aWRlZEluOiBcInJvb3RcIixcclxufSlcclxuZXhwb3J0IGNsYXNzIFNjcmlwdFNlcnZpY2Uge1xyXG4gIHByaXZhdGUgcmVhZG9ubHkgc2NyaXB0RWxlbUlkOiBzdHJpbmcgPSBcIm5neC1jYXRwY2hhLXNjcmlwdFwiO1xyXG5cclxuICAvKipcclxuICAgKiBOYW1lIG9mIHRoZSBnbG9iYWwgZ29vZ2xlIHJlY2FwdGNoYSBzY3JpcHRcclxuICAgKi9cclxuICBwcm90ZWN0ZWQgcmVhZG9ubHkgd2luZG93R3JlY2FwdGNoYSA9IFwiZ3JlY2FwdGNoYVwiO1xyXG5cclxuICAvKipcclxuICAgKiBOYW1lIG9mIGVudGVycGlzZSBwcm9wZXJ0eSBpbiB0aGUgZ2xvYmFsIGdvb2dsZSByZWNhcHRjaGEgc2NyaXB0XHJcbiAgICovXHJcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHdpbmRvd0dyZWNhcHRjaGFFbnRlcnByaXNlID0gXCJlbnRlcnByaXNlXCI7XHJcblxyXG4gIC8qKlxyXG4gICAqIE5hbWUgb2YgdGhlIGdsb2JhbCBjYWxsYmFja1xyXG4gICAqL1xyXG4gIHByb3RlY3RlZCByZWFkb25seSB3aW5kb3dPbkxvYWRDYWxsYmFja1Byb3BlcnR5ID1cclxuICAgIFwibmd4X2NhcHRjaGFfb25sb2FkX2NhbGxiYWNrXCI7XHJcblxyXG4gIC8qKlxyXG4gICAqIE5hbWUgb2YgdGhlIGdsb2JhbCBjYWxsYmFjayBmb3IgZW50ZXJwcmlzZVxyXG4gICAqL1xyXG4gIHByb3RlY3RlZCByZWFkb25seSB3aW5kb3dPbkxvYWRFbnRlcnByaXNlQ2FsbGJhY2tQcm9wZXJ0eSA9XHJcbiAgICBcIm5neF9jYXB0Y2hhX29ubG9hZF9lbnRlcnByaXNlX2NhbGxiYWNrXCI7XHJcblxyXG4gIHByb3RlY3RlZCByZWFkb25seSBnbG9iYWxEb21haW46IHN0cmluZyA9IFwicmVjYXB0Y2hhLm5ldFwiO1xyXG5cclxuICBwcm90ZWN0ZWQgcmVhZG9ubHkgZGVmYXVsdERvbWFpbjogc3RyaW5nID0gXCJnb29nbGUuY29tXCI7XHJcblxyXG4gIHByb3RlY3RlZCByZWFkb25seSBlbnRlcnByaXNlQXBpOiBzdHJpbmcgPSBcImVudGVycHJpc2UuanNcIjtcclxuXHJcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGRlZmF1bHRBcGk6IHN0cmluZyA9IFwiYXBpLmpzXCI7XHJcblxyXG4gIGNvbnN0cnVjdG9yKHByb3RlY3RlZCB6b25lOiBOZ1pvbmUsIEBJbmplY3QoUExBVEZPUk1fSUQpIHByaXZhdGUgcGxhdGZvcm1JZDogT2JqZWN0KSB7IH1cclxuXHJcbiAgcmVnaXN0ZXJDYXB0Y2hhU2NyaXB0KFxyXG4gICAgY29uZmlnOiBSZWNhcHRjaGFDb25maWd1cmF0aW9uLFxyXG4gICAgcmVuZGVyOiBzdHJpbmcsXHJcbiAgICBvbkxvYWQ6IChncmVjYXB0Y2hhOiBhbnkpID0+IHZvaWQsXHJcbiAgICBsYW5ndWFnZT86IHN0cmluZ1xyXG4gICk6IHZvaWQge1xyXG4gICAgaWYgKGlzUGxhdGZvcm1Ccm93c2VyKHRoaXMucGxhdGZvcm1JZCkpIHtcclxuICAgICAgaWYgKHRoaXMuZ3JlY2FwdGNoYVNjcmlwdExvYWRlZChjb25maWcudXNlRW50ZXJwcmlzZSkpIHtcclxuICAgICAgICAvLyByZWNhcHRjaGEgc2NyaXB0IGlzIGFscmVhZHkgbG9hZGVkXHJcbiAgICAgICAgLy8ganVzdCBjYWxsIHRoZSBjYWxsYmFja1xyXG4gICAgICAgIGlmIChjb25maWcudXNlRW50ZXJwcmlzZSkge1xyXG4gICAgICAgICAgdGhpcy56b25lLnJ1bigoKSA9PiB7XHJcbiAgICAgICAgICAgIG9uTG9hZChcclxuICAgICAgICAgICAgICAod2luZG93IGFzIGFueSlbdGhpcy53aW5kb3dHcmVjYXB0Y2hhXVtcclxuICAgICAgICAgICAgICB0aGlzLndpbmRvd0dyZWNhcHRjaGFFbnRlcnByaXNlXHJcbiAgICAgICAgICAgICAgXVxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHRoaXMuem9uZS5ydW4oKCkgPT4ge1xyXG4gICAgICAgICAgICBvbkxvYWQoKHdpbmRvdyBhcyBhbnkpW3RoaXMud2luZG93R3JlY2FwdGNoYV0pO1xyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gd2UgbmVlZCB0byBwYXRjaCB0aGUgY2FsbGJhY2sgdGhyb3VnaCBnbG9iYWwgdmFyaWFibGUsIG90aGVyd2lzZSBjYWxsYmFjayBpcyBub3QgYWNjZXNzaWJsZVxyXG4gICAgICAvLyBub3RlOiBodHRwczovL2dpdGh1Yi5jb20vRW5uZ2FnZS9uZ3gtY2FwdGNoYS9pc3N1ZXMvMlxyXG4gICAgICBpZiAoY29uZmlnLnVzZUVudGVycHJpc2UpIHtcclxuICAgICAgICAod2luZG93IGFzIGFueSlbdGhpcy5nZXRDYWxsYmFja05hbWUodHJ1ZSldID0gPGFueT4oXHJcbiAgICAgICAgICAoKCkgPT5cclxuICAgICAgICAgICAgdGhpcy56b25lLnJ1bihcclxuICAgICAgICAgICAgICBvbkxvYWQuYmluZChcclxuICAgICAgICAgICAgICAgIHRoaXMsXHJcbiAgICAgICAgICAgICAgICAod2luZG93IGFzIGFueSlbdGhpcy53aW5kb3dHcmVjYXB0Y2hhXVtcclxuICAgICAgICAgICAgICAgIHRoaXMud2luZG93R3JlY2FwdGNoYUVudGVycHJpc2VcclxuICAgICAgICAgICAgICAgIF1cclxuICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICkpXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAod2luZG93IGFzIGFueSlbdGhpcy5nZXRDYWxsYmFja05hbWUoZmFsc2UpXSA9IDxhbnk+KFxyXG4gICAgICAgICAgKCgpID0+XHJcbiAgICAgICAgICAgIHRoaXMuem9uZS5ydW4oXHJcbiAgICAgICAgICAgICAgb25Mb2FkLmJpbmQodGhpcywgKHdpbmRvdyBhcyBhbnkpW3RoaXMud2luZG93R3JlY2FwdGNoYV0pXHJcbiAgICAgICAgICAgICkpXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gcHJlcGFyZSBzY3JpcHQgZWxlbVxyXG4gICAgICBjb25zdCBzY3JpcHRFbGVtID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcInNjcmlwdFwiKTtcclxuICAgICAgc2NyaXB0RWxlbS5pZCA9IHRoaXMuc2NyaXB0RWxlbUlkO1xyXG4gICAgICBzY3JpcHRFbGVtLmlubmVySFRNTCA9IFwiXCI7XHJcbiAgICAgIHNjcmlwdEVsZW0uc3JjID0gdGhpcy5nZXRDYXB0Y2hhU2NyaXB0VXJsKGNvbmZpZywgcmVuZGVyLCBsYW5ndWFnZSk7XHJcbiAgICAgIHNjcmlwdEVsZW0uYXN5bmMgPSB0cnVlO1xyXG4gICAgICBzY3JpcHRFbGVtLmRlZmVyID0gdHJ1ZTtcclxuXHJcbiAgICAgIC8vIGFkZCBzY3JpcHQgdG8gaGVhZGVyXHJcbiAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKFwiaGVhZFwiKVswXS5hcHBlbmRDaGlsZChzY3JpcHRFbGVtKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGNsZWFudXAoKTogdm9pZCB7XHJcbiAgICBjb25zdCBlbGVtID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodGhpcy5zY3JpcHRFbGVtSWQpO1xyXG5cclxuICAgIGlmIChlbGVtKSB7XHJcbiAgICAgIGVsZW0ucmVtb3ZlKCk7XHJcbiAgICB9XHJcbiAgICAod2luZG93IGFzIGFueSlbdGhpcy5nZXRDYWxsYmFja05hbWUoKV0gPSB1bmRlZmluZWQ7XHJcbiAgICAod2luZG93IGFzIGFueSlbdGhpcy53aW5kb3dHcmVjYXB0Y2hhXSA9IHVuZGVmaW5lZDtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEluZGljYXRlcyBpZiBnb29nbGUgcmVjYXB0Y2hhIHNjcmlwdCBpcyBhdmFpbGFibGUgYW5kIHJlYWR5IHRvIGJlIHVzZWRcclxuICAgKi9cclxuICBwcml2YXRlIGdyZWNhcHRjaGFTY3JpcHRMb2FkZWQodXNlRW50ZXJwcmlzZT86IGJvb2xlYW4pOiBib29sZWFuIHtcclxuICAgIGlmIChcclxuICAgICAgISh3aW5kb3cgYXMgYW55KVt0aGlzLmdldENhbGxiYWNrTmFtZSh1c2VFbnRlcnByaXNlKV0gfHxcclxuICAgICAgISh3aW5kb3cgYXMgYW55KVt0aGlzLndpbmRvd0dyZWNhcHRjaGFdXHJcbiAgICApIHtcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfSBlbHNlIGlmIChcclxuICAgICAgdXNlRW50ZXJwcmlzZSAmJlxyXG4gICAgICAod2luZG93IGFzIGFueSlbdGhpcy53aW5kb3dHcmVjYXB0Y2hhXVt0aGlzLndpbmRvd0dyZWNhcHRjaGFFbnRlcnByaXNlXVxyXG4gICAgKSB7XHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAvLyBpZiBvbmx5IGVudGVycHJpc2Ugc2NyaXB0IGlzIGxvYWRlZCB3ZSBuZWVkIHRvIGNoZWNrIHNvbWUgdjMncyBtZXRob2RcclxuICAgIH0gZWxzZSBpZiAoKHdpbmRvdyBhcyBhbnkpW3RoaXMud2luZG93R3JlY2FwdGNoYV0uZXhlY3V0ZSkge1xyXG4gICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH1cclxuICAgIHJldHVybiBmYWxzZTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEdldHMgZ2xvYmFsIGNhbGxiYWNrIG5hbWVcclxuICAgKiBAcGFyYW0gdXNlRW50ZXJwcmlzZSBPcHRpb25hbCBmbGFnIGZvciBlbnRlcnByaXNlIHNjcmlwdFxyXG4gICAqIEBwcml2YXRlXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBnZXRDYWxsYmFja05hbWUodXNlRW50ZXJwcmlzZT86IGJvb2xlYW4pOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIHVzZUVudGVycHJpc2VcclxuICAgICAgPyB0aGlzLndpbmRvd09uTG9hZEVudGVycHJpc2VDYWxsYmFja1Byb3BlcnR5XHJcbiAgICAgIDogdGhpcy53aW5kb3dPbkxvYWRDYWxsYmFja1Byb3BlcnR5O1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogR2V0cyBsYW5ndWFnZSBwYXJhbSB1c2VkIGluIHNjcmlwdCB1cmxcclxuICAgKi9cclxuICBwcml2YXRlIGdldExhbmd1YWdlUGFyYW0oaGw/OiBzdHJpbmcpOiBzdHJpbmcge1xyXG4gICAgaWYgKCFobCkge1xyXG4gICAgICByZXR1cm4gXCJcIjtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gYCZobD0ke2hsfWA7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBVcmwgdG8gZ29vZ2xlIGFwaSBzY3JpcHRcclxuICAgKi9cclxuICBwcml2YXRlIGdldENhcHRjaGFTY3JpcHRVcmwoXHJcbiAgICBjb25maWc6IFJlY2FwdGNoYUNvbmZpZ3VyYXRpb24sXHJcbiAgICByZW5kZXI6IHN0cmluZyxcclxuICAgIGxhbmd1YWdlPzogc3RyaW5nXHJcbiAgKTogc3RyaW5nIHtcclxuICAgIGNvbnN0IGRvbWFpbiA9IGNvbmZpZy51c2VHbG9iYWxEb21haW5cclxuICAgICAgPyB0aGlzLmdsb2JhbERvbWFpblxyXG4gICAgICA6IHRoaXMuZGVmYXVsdERvbWFpbjtcclxuICAgIGNvbnN0IGFwaSA9IGNvbmZpZy51c2VFbnRlcnByaXNlID8gdGhpcy5lbnRlcnByaXNlQXBpIDogdGhpcy5kZWZhdWx0QXBpO1xyXG4gICAgY29uc3QgY2FsbGJhY2sgPSB0aGlzLmdldENhbGxiYWNrTmFtZShjb25maWcudXNlRW50ZXJwcmlzZSk7XHJcblxyXG4gICAgcmV0dXJuIGBodHRwczovL3d3dy4ke2RvbWFpbn0vcmVjYXB0Y2hhLyR7YXBpfT9vbmxvYWQ9JHtjYWxsYmFja30mcmVuZGVyPSR7cmVuZGVyfSR7dGhpcy5nZXRMYW5ndWFnZVBhcmFtKFxyXG4gICAgICBsYW5ndWFnZVxyXG4gICAgKX1gO1xyXG4gIH1cclxufVxyXG4iXX0=