ngx-captcha.mjs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  1. import * as i0 from '@angular/core';
  2. import { Injectable, EventEmitter, InjectFlags, Directive, Input, Output, forwardRef, Component, ViewChild, NgModule } from '@angular/core';
  3. import { NgControl, NG_VALUE_ACCESSOR } from '@angular/forms';
  4. import { CommonModule } from '@angular/common';
  5. class ScriptService {
  6. constructor(zone) {
  7. this.zone = zone;
  8. this.scriptElemId = "ngx-catpcha-script";
  9. /**
  10. * Name of the global google recaptcha script
  11. */
  12. this.windowGrecaptcha = "grecaptcha";
  13. /**
  14. * Name of enterpise property in the global google recaptcha script
  15. */
  16. this.windowGrecaptchaEnterprise = "enterprise";
  17. /**
  18. * Name of the global callback
  19. */
  20. this.windowOnLoadCallbackProperty = "ngx_captcha_onload_callback";
  21. /**
  22. * Name of the global callback for enterprise
  23. */
  24. this.windowOnLoadEnterpriseCallbackProperty = "ngx_captcha_onload_enterprise_callback";
  25. this.globalDomain = "recaptcha.net";
  26. this.defaultDomain = "google.com";
  27. this.enterpriseApi = "enterprise.js";
  28. this.defaultApi = "api.js";
  29. }
  30. registerCaptchaScript(config, render, onLoad, language) {
  31. if (this.grecaptchaScriptLoaded(config.useEnterprise)) {
  32. // recaptcha script is already loaded
  33. // just call the callback
  34. if (config.useEnterprise) {
  35. this.zone.run(() => {
  36. onLoad(window[this.windowGrecaptcha][this.windowGrecaptchaEnterprise]);
  37. });
  38. }
  39. else {
  40. this.zone.run(() => {
  41. onLoad(window[this.windowGrecaptcha]);
  42. });
  43. }
  44. return;
  45. }
  46. // we need to patch the callback through global variable, otherwise callback is not accessible
  47. // note: https://github.com/Enngage/ngx-captcha/issues/2
  48. if (config.useEnterprise) {
  49. window[this.getCallbackName(true)] = ((() => this.zone.run(onLoad.bind(this, window[this.windowGrecaptcha][this.windowGrecaptchaEnterprise]))));
  50. }
  51. else {
  52. window[this.getCallbackName(false)] = ((() => this.zone.run(onLoad.bind(this, window[this.windowGrecaptcha]))));
  53. }
  54. // prepare script elem
  55. const scriptElem = document.createElement("script");
  56. scriptElem.id = this.scriptElemId;
  57. scriptElem.innerHTML = "";
  58. scriptElem.src = this.getCaptchaScriptUrl(config, render, language);
  59. scriptElem.async = true;
  60. scriptElem.defer = true;
  61. // add script to header
  62. document.getElementsByTagName("head")[0].appendChild(scriptElem);
  63. }
  64. cleanup() {
  65. const elem = document.getElementById(this.scriptElemId);
  66. if (elem) {
  67. elem.remove();
  68. }
  69. window[this.getCallbackName()] = undefined;
  70. window[this.windowGrecaptcha] = undefined;
  71. }
  72. /**
  73. * Indicates if google recaptcha script is available and ready to be used
  74. */
  75. grecaptchaScriptLoaded(useEnterprise) {
  76. if (!window[this.getCallbackName(useEnterprise)] ||
  77. !window[this.windowGrecaptcha]) {
  78. return false;
  79. }
  80. else if (useEnterprise &&
  81. window[this.windowGrecaptcha][this.windowGrecaptchaEnterprise]) {
  82. return true;
  83. // if only enterprise script is loaded we need to check some v3's method
  84. }
  85. else if (window[this.windowGrecaptcha].execute) {
  86. return true;
  87. }
  88. return false;
  89. }
  90. /**
  91. * Gets global callback name
  92. * @param useEnterprise Optional flag for enterprise script
  93. * @private
  94. */
  95. getCallbackName(useEnterprise) {
  96. return useEnterprise
  97. ? this.windowOnLoadEnterpriseCallbackProperty
  98. : this.windowOnLoadCallbackProperty;
  99. }
  100. /**
  101. * Gets language param used in script url
  102. */
  103. getLanguageParam(hl) {
  104. if (!hl) {
  105. return "";
  106. }
  107. return `&hl=${hl}`;
  108. }
  109. /**
  110. * Url to google api script
  111. */
  112. getCaptchaScriptUrl(config, render, language) {
  113. const domain = config.useGlobalDomain
  114. ? this.globalDomain
  115. : this.defaultDomain;
  116. const api = config.useEnterprise ? this.enterpriseApi : this.defaultApi;
  117. const callback = this.getCallbackName(config.useEnterprise);
  118. return `https://www.${domain}/recaptcha/${api}?onload=${callback}&render=${render}${this.getLanguageParam(language)}`;
  119. }
  120. }
  121. /** @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 });
  122. /** @nocollapse */ ScriptService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: ScriptService, providedIn: "root" });
  123. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: ScriptService, decorators: [{
  124. type: Injectable,
  125. args: [{
  126. providedIn: "root",
  127. }]
  128. }], ctorParameters: function () { return [{ type: i0.NgZone }]; } });
  129. class BaseReCaptchaComponentDirective {
  130. constructor(renderer, zone, injector, scriptService) {
  131. this.renderer = renderer;
  132. this.zone = zone;
  133. this.injector = injector;
  134. this.scriptService = scriptService;
  135. /**
  136. * Prefix of the captcha element
  137. */
  138. this.captchaElemPrefix = "ngx_captcha_id_";
  139. this.setupCaptcha = true;
  140. /**
  141. * Indicates if global domain 'recaptcha.net' should be used instead of default domain ('google.com')
  142. */
  143. this.useGlobalDomain = false;
  144. this.useEnterprise = false;
  145. /**
  146. * Type
  147. */
  148. this.type = "image";
  149. /**
  150. * Tab index
  151. */
  152. this.tabIndex = 0;
  153. /**
  154. * Called when captcha receives successful response.
  155. * Captcha response token is passed to event.
  156. */
  157. this.success = new EventEmitter();
  158. /**
  159. * Called when captcha is loaded. Event receives id of the captcha
  160. */
  161. this.load = new EventEmitter();
  162. /**
  163. * Called when captcha is reset.
  164. */
  165. this.reset = new EventEmitter();
  166. /**
  167. * Called when captcha is loaded & ready. I.e. when you need to execute captcha on component load.
  168. */
  169. this.ready = new EventEmitter();
  170. /**
  171. * Error callback
  172. */
  173. this.error = new EventEmitter();
  174. /**
  175. * Expired callback
  176. */
  177. this.expire = new EventEmitter();
  178. /**
  179. * Indicates if captcha should be set on load
  180. */
  181. this.setupAfterLoad = false;
  182. /**
  183. * If enabled, captcha will reset after receiving success response. This is useful
  184. * when invisible captcha need to be resolved multiple times on same page
  185. */
  186. this.resetCaptchaAfterSuccess = false;
  187. /**
  188. * Required by ControlValueAccessor
  189. */
  190. this.onChange = (val) => { };
  191. this.onTouched = (val) => { };
  192. /**
  193. * Indicates if captcha is loaded
  194. */
  195. this.isLoaded = false;
  196. }
  197. ngAfterViewInit() {
  198. var _a;
  199. this.control = (_a = this.injector.get(NgControl, undefined, InjectFlags.Optional)) === null || _a === void 0 ? void 0 : _a.control;
  200. }
  201. ngAfterViewChecked() {
  202. if (this.setupCaptcha) {
  203. this.setupCaptcha = false;
  204. this.setupComponent();
  205. }
  206. }
  207. ngOnChanges(changes) {
  208. // cleanup scripts if language changed because they need to be reloaded
  209. if (changes && changes.hl) {
  210. // cleanup scripts when language changes
  211. if (!changes.hl.firstChange &&
  212. changes.hl.currentValue !== changes.hl.previousValue) {
  213. this.scriptService.cleanup();
  214. }
  215. }
  216. if (changes && changes.useGlobalDomain) {
  217. // cleanup scripts when domain changes
  218. if (!changes.useGlobalDomain.firstChange &&
  219. changes.useGlobalDomain.currentValue !==
  220. changes.useGlobalDomain.previousValue) {
  221. this.scriptService.cleanup();
  222. }
  223. }
  224. this.setupCaptcha = true;
  225. }
  226. /**
  227. * Gets captcha response as per reCaptcha docs
  228. */
  229. getResponse() {
  230. return this.reCaptchaApi.getResponse(this.captchaId);
  231. }
  232. /**
  233. * Gets Id of captcha widget
  234. */
  235. getCaptchaId() {
  236. return this.captchaId;
  237. }
  238. /**
  239. * Resets captcha
  240. */
  241. resetCaptcha() {
  242. this.zone.run(() => {
  243. // reset captcha using Google js api
  244. this.reCaptchaApi.reset();
  245. // required due to forms
  246. this.onChange(undefined);
  247. this.onTouched(undefined);
  248. // trigger reset event
  249. this.reset.next();
  250. });
  251. }
  252. /**
  253. * Gets last submitted captcha response
  254. */
  255. getCurrentResponse() {
  256. return this.currentResponse;
  257. }
  258. /**
  259. * Reload captcha. Useful when properties (i.e. theme) changed and captcha need to reflect them
  260. */
  261. reloadCaptcha() {
  262. this.setupComponent();
  263. }
  264. ensureCaptchaElem(captchaElemId) {
  265. const captchaElem = document.getElementById(captchaElemId);
  266. if (!captchaElem) {
  267. throw Error(`Captcha element with id '${captchaElemId}' was not found`);
  268. }
  269. // assign captcha alem
  270. this.captchaElem = captchaElem;
  271. }
  272. /**
  273. * Responsible for instantiating captcha element
  274. */
  275. renderReCaptcha() {
  276. // run outside angular zone due to timeout issues when testing
  277. // details: https://github.com/Enngage/ngx-captcha/issues/26
  278. this.zone.runOutsideAngular(() => {
  279. // to fix reCAPTCHA placeholder element must be an element or id
  280. // https://github.com/Enngage/ngx-captcha/issues/96
  281. setTimeout(() => {
  282. this.captchaId = this.reCaptchaApi.render(this.captchaElemId, this.getCaptchaProperties());
  283. this.ready.next();
  284. }, 0);
  285. });
  286. }
  287. /**
  288. * Called when captcha receives response
  289. * @param callback Callback
  290. */
  291. handleCallback(callback) {
  292. this.currentResponse = callback;
  293. this.success.next(callback);
  294. this.zone.run(() => {
  295. this.onChange(callback);
  296. this.onTouched(callback);
  297. });
  298. if (this.resetCaptchaAfterSuccess) {
  299. this.resetCaptcha();
  300. }
  301. }
  302. getPseudoUniqueNumber() {
  303. return new Date().getUTCMilliseconds() + Math.floor(Math.random() * 9999);
  304. }
  305. setupComponent() {
  306. // captcha specific setup
  307. this.captchaSpecificSetup();
  308. // create captcha wrapper
  309. this.createAndSetCaptchaElem();
  310. this.scriptService.registerCaptchaScript({
  311. useGlobalDomain: this.useGlobalDomain,
  312. useEnterprise: this.useEnterprise,
  313. }, "explicit", (grecaptcha) => {
  314. this.onloadCallback(grecaptcha);
  315. }, this.hl);
  316. }
  317. /**
  318. * Called when google's recaptcha script is ready
  319. */
  320. onloadCallback(grecapcha) {
  321. // assign reference to reCaptcha Api once its loaded
  322. this.reCaptchaApi = grecapcha;
  323. if (!this.reCaptchaApi) {
  324. throw Error(`ReCaptcha Api was not initialized correctly`);
  325. }
  326. // loaded flag
  327. this.isLoaded = true;
  328. // fire load event
  329. this.load.next();
  330. // render captcha
  331. this.renderReCaptcha();
  332. // setup component if it was flagged as such
  333. if (this.setupAfterLoad) {
  334. this.setupAfterLoad = false;
  335. this.setupComponent();
  336. }
  337. }
  338. generateNewElemId() {
  339. return this.captchaElemPrefix + this.getPseudoUniqueNumber();
  340. }
  341. createAndSetCaptchaElem() {
  342. // generate new captcha id
  343. this.captchaElemId = this.generateNewElemId();
  344. if (!this.captchaElemId) {
  345. throw Error(`Captcha elem Id is not set`);
  346. }
  347. if (!this.captchaWrapperElem) {
  348. throw Error(`Captcha DOM element is not initialized`);
  349. }
  350. // remove old html
  351. this.captchaWrapperElem.nativeElement.innerHTML = "";
  352. // create new wrapper for captcha
  353. const newElem = this.renderer.createElement("div");
  354. newElem.id = this.captchaElemId;
  355. this.renderer.appendChild(this.captchaWrapperElem.nativeElement, newElem);
  356. // when use captcha in cdk stepper then throwing error Captcha element with id 'ngx_captcha_id_XXXX' not found
  357. // to fix it checking ensureCaptchaElem in timeout so that its check in next call and its able to find element
  358. setTimeout(() => {
  359. // update captcha elem
  360. if (this.captchaElemId) {
  361. this.ensureCaptchaElem(this.captchaElemId);
  362. }
  363. }, 0);
  364. }
  365. /**
  366. * To be aligned with the ControlValueAccessor interface we need to implement this method
  367. * However as we don't want to update the recaptcha, this doesn't need to be implemented
  368. */
  369. writeValue(obj) { }
  370. /**
  371. * This method helps us tie together recaptcha and our formControl values
  372. */
  373. registerOnChange(fn) {
  374. this.onChange = fn;
  375. }
  376. /**
  377. * At some point we might be interested whether the user has touched our component
  378. */
  379. registerOnTouched(fn) {
  380. this.onTouched = fn;
  381. }
  382. /**
  383. * Handles error callback
  384. */
  385. handleErrorCallback() {
  386. this.zone.run(() => {
  387. this.onChange(undefined);
  388. this.onTouched(undefined);
  389. });
  390. this.error.next();
  391. }
  392. /**
  393. * Handles expired callback
  394. */
  395. handleExpireCallback() {
  396. this.expire.next();
  397. // reset captcha on expire callback
  398. this.resetCaptcha();
  399. }
  400. }
  401. /** @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 });
  402. /** @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 });
  403. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: BaseReCaptchaComponentDirective, decorators: [{
  404. type: Directive
  405. }], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.NgZone }, { type: i0.Injector }, { type: ScriptService }]; }, propDecorators: { siteKey: [{
  406. type: Input
  407. }], useGlobalDomain: [{
  408. type: Input
  409. }], useEnterprise: [{
  410. type: Input
  411. }], type: [{
  412. type: Input
  413. }], hl: [{
  414. type: Input
  415. }], tabIndex: [{
  416. type: Input
  417. }], success: [{
  418. type: Output
  419. }], load: [{
  420. type: Output
  421. }], reset: [{
  422. type: Output
  423. }], ready: [{
  424. type: Output
  425. }], error: [{
  426. type: Output
  427. }], expire: [{
  428. type: Output
  429. }] } });
  430. var ReCaptchaType;
  431. (function (ReCaptchaType) {
  432. ReCaptchaType[ReCaptchaType["InvisibleReCaptcha"] = 0] = "InvisibleReCaptcha";
  433. ReCaptchaType[ReCaptchaType["ReCaptcha2"] = 1] = "ReCaptcha2";
  434. })(ReCaptchaType || (ReCaptchaType = {}));
  435. class InvisibleReCaptchaComponent extends BaseReCaptchaComponentDirective {
  436. constructor(renderer, zone, injector, scriptService) {
  437. super(renderer, zone, injector, scriptService);
  438. this.renderer = renderer;
  439. this.zone = zone;
  440. this.injector = injector;
  441. this.scriptService = scriptService;
  442. /**
  443. * This size representing invisible captcha
  444. */
  445. this.size = 'invisible';
  446. /**
  447. * Theme
  448. */
  449. this.theme = 'light';
  450. /**
  451. * Badge
  452. */
  453. this.badge = 'bottomright';
  454. this.recaptchaType = ReCaptchaType.InvisibleReCaptcha;
  455. }
  456. ngOnChanges(changes) {
  457. super.ngOnChanges(changes);
  458. }
  459. /**
  460. * Programatically invoke the reCAPTCHA check. Used if the invisible reCAPTCHA is on a div instead of a button.
  461. */
  462. execute() {
  463. // execute captcha
  464. this.zone.runOutsideAngular(() => this.reCaptchaApi.execute(this.captchaId));
  465. }
  466. captchaSpecificSetup() {
  467. }
  468. /**
  469. * Gets reCaptcha properties
  470. */
  471. getCaptchaProperties() {
  472. return {
  473. 'sitekey': this.siteKey,
  474. 'callback': (response) => this.zone.run(() => this.handleCallback(response)),
  475. 'expired-callback': () => this.zone.run(() => this.handleExpireCallback()),
  476. 'error-callback': () => this.zone.run(() => this.handleErrorCallback()),
  477. 'badge': this.badge,
  478. 'type': this.type,
  479. 'tabindex': this.tabIndex,
  480. 'size': this.size,
  481. 'theme': this.theme
  482. };
  483. }
  484. }
  485. /** @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 });
  486. /** @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: [
  487. {
  488. provide: NG_VALUE_ACCESSOR,
  489. useExisting: forwardRef((() => InvisibleReCaptchaComponent)),
  490. multi: true,
  491. }
  492. ], viewQueries: [{ propertyName: "captchaWrapperElem", first: true, predicate: ["captchaWrapperElem"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: `
  493. <div #captchaWrapperElem></div>`, isInline: true });
  494. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: InvisibleReCaptchaComponent, decorators: [{
  495. type: Component,
  496. args: [{
  497. selector: 'ngx-invisible-recaptcha',
  498. template: `
  499. <div #captchaWrapperElem></div>`,
  500. providers: [
  501. {
  502. provide: NG_VALUE_ACCESSOR,
  503. useExisting: forwardRef((() => InvisibleReCaptchaComponent)),
  504. multi: true,
  505. }
  506. ]
  507. }]
  508. }], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.NgZone }, { type: i0.Injector }, { type: ScriptService }]; }, propDecorators: { theme: [{
  509. type: Input
  510. }], badge: [{
  511. type: Input
  512. }], captchaWrapperElem: [{
  513. type: ViewChild,
  514. args: ['captchaWrapperElem', { static: false }]
  515. }] } });
  516. class ReCaptcha2Component extends BaseReCaptchaComponentDirective {
  517. constructor(renderer, zone, injector, scriptService) {
  518. super(renderer, zone, injector, scriptService);
  519. this.renderer = renderer;
  520. this.zone = zone;
  521. this.injector = injector;
  522. this.scriptService = scriptService;
  523. /**
  524. * Name of the global expire callback
  525. */
  526. this.windowOnErrorCallbackProperty = 'ngx_captcha_error_callback';
  527. /**
  528. * Name of the global error callback
  529. */
  530. this.windowOnExpireCallbackProperty = 'ngx_captcha_expire_callback';
  531. /**
  532. * Theme
  533. */
  534. this.theme = 'light';
  535. /**
  536. * Size
  537. */
  538. this.size = 'normal';
  539. this.recaptchaType = ReCaptchaType.ReCaptcha2;
  540. }
  541. ngOnChanges(changes) {
  542. super.ngOnChanges(changes);
  543. }
  544. ngOnDestroy() {
  545. window[this.windowOnErrorCallbackProperty] = {};
  546. window[this.windowOnExpireCallbackProperty] = {};
  547. }
  548. captchaSpecificSetup() {
  549. this.registerCallbacks();
  550. }
  551. /**
  552. * Gets reCaptcha properties
  553. */
  554. getCaptchaProperties() {
  555. return {
  556. 'sitekey': this.siteKey,
  557. 'callback': (response) => this.zone.run(() => this.handleCallback(response)),
  558. 'expired-callback': () => this.zone.run(() => this.handleExpireCallback()),
  559. 'error-callback': () => this.zone.run(() => this.handleErrorCallback()),
  560. 'theme': this.theme,
  561. 'type': this.type,
  562. 'size': this.size,
  563. 'tabindex': this.tabIndex
  564. };
  565. }
  566. /**
  567. * Registers global callbacks
  568. */
  569. registerCallbacks() {
  570. window[this.windowOnErrorCallbackProperty] = super.handleErrorCallback.bind(this);
  571. window[this.windowOnExpireCallbackProperty] = super.handleExpireCallback.bind(this);
  572. }
  573. }
  574. /** @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 });
  575. /** @nocollapse */ ReCaptcha2Component.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.0.4", type: ReCaptcha2Component, selector: "ngx-recaptcha2", inputs: { theme: "theme", size: "size" }, providers: [
  576. {
  577. provide: NG_VALUE_ACCESSOR,
  578. useExisting: forwardRef((() => ReCaptcha2Component)),
  579. multi: true,
  580. }
  581. ], viewQueries: [{ propertyName: "captchaWrapperElem", first: true, predicate: ["captchaWrapperElem"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: `
  582. <div #captchaWrapperElem></div>`, isInline: true });
  583. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: ReCaptcha2Component, decorators: [{
  584. type: Component,
  585. args: [{
  586. selector: 'ngx-recaptcha2',
  587. template: `
  588. <div #captchaWrapperElem></div>`,
  589. providers: [
  590. {
  591. provide: NG_VALUE_ACCESSOR,
  592. useExisting: forwardRef((() => ReCaptcha2Component)),
  593. multi: true,
  594. }
  595. ]
  596. }]
  597. }], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.NgZone }, { type: i0.Injector }, { type: ScriptService }]; }, propDecorators: { theme: [{
  598. type: Input
  599. }], size: [{
  600. type: Input
  601. }], captchaWrapperElem: [{
  602. type: ViewChild,
  603. args: ['captchaWrapperElem', { static: false }]
  604. }] } });
  605. class ReCaptchaV3Service {
  606. constructor(scriptService, zone) {
  607. this.scriptService = scriptService;
  608. this.zone = zone;
  609. }
  610. /**
  611. * Executes reCaptcha v3/Enterprise with given action and passes token via callback. You need to verify
  612. * this callback in your backend to get meaningful results.
  613. *
  614. * For more information see https://developers.google.com/recaptcha/docs/v3
  615. * For enterprise see https://cloud.google.com/recaptcha-enterprise/docs
  616. *
  617. * @param siteKey Site key found in your google admin panel
  618. * @param action Action to log
  619. * @param callback Callback function to to handle token
  620. * @param config Optional configuration like useGlobalDomain to be provided
  621. * @param errorCallback Optional Callback function to handle errors
  622. */
  623. execute(siteKey, action, callback, config, errorCallback) {
  624. this.executeAsPromise(siteKey, action, config)
  625. .then(callback)
  626. .catch((error) => errorCallback ? errorCallback(error) : console.error(error));
  627. }
  628. /**
  629. * Executes reCaptcha v3/Enterprise with given action and returns token via Promise. You need to verify
  630. * this token in your backend to get meaningful results.
  631. *
  632. * For more information see https://developers.google.com/recaptcha/docs/v3
  633. * For enterprise see https://cloud.google.com/recaptcha-enterprise/docs
  634. *
  635. * @param siteKey Site key found in your google admin panel
  636. * @param action Action to log
  637. * @param config Optional configuration like useGlobalDomain to be provided
  638. */
  639. executeAsPromise(siteKey, action, config) {
  640. return new Promise((resolve, reject) => {
  641. const configuration = config || {};
  642. const onRegister = (grecaptcha) => {
  643. this.zone.runOutsideAngular(() => {
  644. try {
  645. grecaptcha
  646. .execute(siteKey, { action })
  647. .then((token) => this.zone.run(() => resolve(token)));
  648. }
  649. catch (error) {
  650. reject(error);
  651. }
  652. });
  653. };
  654. this.scriptService.registerCaptchaScript(configuration, siteKey, onRegister);
  655. });
  656. }
  657. }
  658. /** @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 });
  659. /** @nocollapse */ ReCaptchaV3Service.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: ReCaptchaV3Service, providedIn: "root" });
  660. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: ReCaptchaV3Service, decorators: [{
  661. type: Injectable,
  662. args: [{
  663. providedIn: "root",
  664. }]
  665. }], ctorParameters: function () { return [{ type: ScriptService }, { type: i0.NgZone }]; } });
  666. class NgxCaptchaModule {
  667. }
  668. /** @nocollapse */ NgxCaptchaModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: NgxCaptchaModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
  669. /** @nocollapse */ NgxCaptchaModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.0.4", ngImport: i0, type: NgxCaptchaModule, declarations: [ReCaptcha2Component,
  670. InvisibleReCaptchaComponent], imports: [CommonModule], exports: [ReCaptcha2Component,
  671. InvisibleReCaptchaComponent] });
  672. /** @nocollapse */ NgxCaptchaModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: NgxCaptchaModule, providers: [
  673. ScriptService,
  674. ReCaptchaV3Service
  675. ], imports: [CommonModule] });
  676. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: NgxCaptchaModule, decorators: [{
  677. type: NgModule,
  678. args: [{
  679. imports: [
  680. CommonModule
  681. ],
  682. declarations: [
  683. ReCaptcha2Component,
  684. InvisibleReCaptchaComponent
  685. ],
  686. providers: [
  687. ScriptService,
  688. ReCaptchaV3Service
  689. ],
  690. exports: [
  691. ReCaptcha2Component,
  692. InvisibleReCaptchaComponent
  693. ]
  694. }]
  695. }] });
  696. /*
  697. * Public API
  698. */
  699. /**
  700. * Generated bundle index. Do not edit.
  701. */
  702. export { BaseReCaptchaComponentDirective, InvisibleReCaptchaComponent, NgxCaptchaModule, ReCaptcha2Component, ReCaptchaType, ReCaptchaV3Service, ScriptService };
  703. //# sourceMappingURL=ngx-captcha.mjs.map