ngx-captcha.mjs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712
  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. this.control = this.injector.get(NgControl, undefined, InjectFlags.Optional)?.control;
  199. }
  200. ngAfterViewChecked() {
  201. if (this.setupCaptcha) {
  202. this.setupCaptcha = false;
  203. this.setupComponent();
  204. }
  205. }
  206. ngOnChanges(changes) {
  207. // cleanup scripts if language changed because they need to be reloaded
  208. if (changes && changes.hl) {
  209. // cleanup scripts when language changes
  210. if (!changes.hl.firstChange &&
  211. changes.hl.currentValue !== changes.hl.previousValue) {
  212. this.scriptService.cleanup();
  213. }
  214. }
  215. if (changes && changes.useGlobalDomain) {
  216. // cleanup scripts when domain changes
  217. if (!changes.useGlobalDomain.firstChange &&
  218. changes.useGlobalDomain.currentValue !==
  219. changes.useGlobalDomain.previousValue) {
  220. this.scriptService.cleanup();
  221. }
  222. }
  223. this.setupCaptcha = true;
  224. }
  225. /**
  226. * Gets captcha response as per reCaptcha docs
  227. */
  228. getResponse() {
  229. return this.reCaptchaApi.getResponse(this.captchaId);
  230. }
  231. /**
  232. * Gets Id of captcha widget
  233. */
  234. getCaptchaId() {
  235. return this.captchaId;
  236. }
  237. /**
  238. * Resets captcha
  239. */
  240. resetCaptcha() {
  241. this.zone.run(() => {
  242. // reset captcha using Google js api
  243. this.reCaptchaApi.reset();
  244. // required due to forms
  245. this.onChange(undefined);
  246. this.onTouched(undefined);
  247. // trigger reset event
  248. this.reset.next();
  249. });
  250. }
  251. /**
  252. * Gets last submitted captcha response
  253. */
  254. getCurrentResponse() {
  255. return this.currentResponse;
  256. }
  257. /**
  258. * Reload captcha. Useful when properties (i.e. theme) changed and captcha need to reflect them
  259. */
  260. reloadCaptcha() {
  261. this.setupComponent();
  262. }
  263. ensureCaptchaElem(captchaElemId) {
  264. const captchaElem = document.getElementById(captchaElemId);
  265. if (!captchaElem) {
  266. throw Error(`Captcha element with id '${captchaElemId}' was not found`);
  267. }
  268. // assign captcha alem
  269. this.captchaElem = captchaElem;
  270. }
  271. /**
  272. * Responsible for instantiating captcha element
  273. */
  274. renderReCaptcha() {
  275. // run outside angular zone due to timeout issues when testing
  276. // details: https://github.com/Enngage/ngx-captcha/issues/26
  277. this.zone.runOutsideAngular(() => {
  278. // to fix reCAPTCHA placeholder element must be an element or id
  279. // https://github.com/Enngage/ngx-captcha/issues/96
  280. setTimeout(() => {
  281. this.captchaId = this.reCaptchaApi.render(this.captchaElemId, this.getCaptchaProperties());
  282. this.ready.next();
  283. }, 0);
  284. });
  285. }
  286. /**
  287. * Called when captcha receives response
  288. * @param callback Callback
  289. */
  290. handleCallback(callback) {
  291. this.currentResponse = callback;
  292. this.success.next(callback);
  293. this.zone.run(() => {
  294. this.onChange(callback);
  295. this.onTouched(callback);
  296. });
  297. if (this.resetCaptchaAfterSuccess) {
  298. this.resetCaptcha();
  299. }
  300. }
  301. getPseudoUniqueNumber() {
  302. return new Date().getUTCMilliseconds() + Math.floor(Math.random() * 9999);
  303. }
  304. setupComponent() {
  305. // captcha specific setup
  306. this.captchaSpecificSetup();
  307. // create captcha wrapper
  308. this.createAndSetCaptchaElem();
  309. this.scriptService.registerCaptchaScript({
  310. useGlobalDomain: this.useGlobalDomain,
  311. useEnterprise: this.useEnterprise,
  312. }, "explicit", (grecaptcha) => {
  313. this.onloadCallback(grecaptcha);
  314. }, this.hl);
  315. }
  316. /**
  317. * Called when google's recaptcha script is ready
  318. */
  319. onloadCallback(grecapcha) {
  320. // assign reference to reCaptcha Api once its loaded
  321. this.reCaptchaApi = grecapcha;
  322. if (!this.reCaptchaApi) {
  323. throw Error(`ReCaptcha Api was not initialized correctly`);
  324. }
  325. // loaded flag
  326. this.isLoaded = true;
  327. // fire load event
  328. this.load.next();
  329. // render captcha
  330. this.renderReCaptcha();
  331. // setup component if it was flagged as such
  332. if (this.setupAfterLoad) {
  333. this.setupAfterLoad = false;
  334. this.setupComponent();
  335. }
  336. }
  337. generateNewElemId() {
  338. return this.captchaElemPrefix + this.getPseudoUniqueNumber();
  339. }
  340. createAndSetCaptchaElem() {
  341. // generate new captcha id
  342. this.captchaElemId = this.generateNewElemId();
  343. if (!this.captchaElemId) {
  344. throw Error(`Captcha elem Id is not set`);
  345. }
  346. if (!this.captchaWrapperElem) {
  347. throw Error(`Captcha DOM element is not initialized`);
  348. }
  349. // remove old html
  350. this.captchaWrapperElem.nativeElement.innerHTML = "";
  351. // create new wrapper for captcha
  352. const newElem = this.renderer.createElement("div");
  353. newElem.id = this.captchaElemId;
  354. this.renderer.appendChild(this.captchaWrapperElem.nativeElement, newElem);
  355. // when use captcha in cdk stepper then throwing error Captcha element with id 'ngx_captcha_id_XXXX' not found
  356. // to fix it checking ensureCaptchaElem in timeout so that its check in next call and its able to find element
  357. setTimeout(() => {
  358. // update captcha elem
  359. if (this.captchaElemId) {
  360. this.ensureCaptchaElem(this.captchaElemId);
  361. }
  362. }, 0);
  363. }
  364. /**
  365. * To be aligned with the ControlValueAccessor interface we need to implement this method
  366. * However as we don't want to update the recaptcha, this doesn't need to be implemented
  367. */
  368. writeValue(obj) { }
  369. /**
  370. * This method helps us tie together recaptcha and our formControl values
  371. */
  372. registerOnChange(fn) {
  373. this.onChange = fn;
  374. }
  375. /**
  376. * At some point we might be interested whether the user has touched our component
  377. */
  378. registerOnTouched(fn) {
  379. this.onTouched = fn;
  380. }
  381. /**
  382. * Handles error callback
  383. */
  384. handleErrorCallback() {
  385. this.zone.run(() => {
  386. this.onChange(undefined);
  387. this.onTouched(undefined);
  388. });
  389. this.error.next();
  390. }
  391. /**
  392. * Handles expired callback
  393. */
  394. handleExpireCallback() {
  395. this.expire.next();
  396. // reset captcha on expire callback
  397. this.resetCaptcha();
  398. }
  399. }
  400. /** @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 });
  401. /** @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 });
  402. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: BaseReCaptchaComponentDirective, decorators: [{
  403. type: Directive
  404. }], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.NgZone }, { type: i0.Injector }, { type: ScriptService }]; }, propDecorators: { siteKey: [{
  405. type: Input
  406. }], useGlobalDomain: [{
  407. type: Input
  408. }], useEnterprise: [{
  409. type: Input
  410. }], type: [{
  411. type: Input
  412. }], hl: [{
  413. type: Input
  414. }], tabIndex: [{
  415. type: Input
  416. }], success: [{
  417. type: Output
  418. }], load: [{
  419. type: Output
  420. }], reset: [{
  421. type: Output
  422. }], ready: [{
  423. type: Output
  424. }], error: [{
  425. type: Output
  426. }], expire: [{
  427. type: Output
  428. }] } });
  429. var ReCaptchaType;
  430. (function (ReCaptchaType) {
  431. ReCaptchaType[ReCaptchaType["InvisibleReCaptcha"] = 0] = "InvisibleReCaptcha";
  432. ReCaptchaType[ReCaptchaType["ReCaptcha2"] = 1] = "ReCaptcha2";
  433. })(ReCaptchaType || (ReCaptchaType = {}));
  434. class InvisibleReCaptchaComponent extends BaseReCaptchaComponentDirective {
  435. constructor(renderer, zone, injector, scriptService) {
  436. super(renderer, zone, injector, scriptService);
  437. this.renderer = renderer;
  438. this.zone = zone;
  439. this.injector = injector;
  440. this.scriptService = scriptService;
  441. /**
  442. * This size representing invisible captcha
  443. */
  444. this.size = 'invisible';
  445. /**
  446. * Theme
  447. */
  448. this.theme = 'light';
  449. /**
  450. * Badge
  451. */
  452. this.badge = 'bottomright';
  453. this.recaptchaType = ReCaptchaType.InvisibleReCaptcha;
  454. }
  455. ngOnChanges(changes) {
  456. super.ngOnChanges(changes);
  457. }
  458. /**
  459. * Programatically invoke the reCAPTCHA check. Used if the invisible reCAPTCHA is on a div instead of a button.
  460. */
  461. execute() {
  462. // execute captcha
  463. this.zone.runOutsideAngular(() => this.reCaptchaApi.execute(this.captchaId));
  464. }
  465. captchaSpecificSetup() {
  466. }
  467. /**
  468. * Gets reCaptcha properties
  469. */
  470. getCaptchaProperties() {
  471. return {
  472. 'sitekey': this.siteKey,
  473. 'callback': (response) => this.zone.run(() => this.handleCallback(response)),
  474. 'expired-callback': () => this.zone.run(() => this.handleExpireCallback()),
  475. 'error-callback': () => this.zone.run(() => this.handleErrorCallback()),
  476. 'badge': this.badge,
  477. 'type': this.type,
  478. 'tabindex': this.tabIndex,
  479. 'size': this.size,
  480. 'theme': this.theme
  481. };
  482. }
  483. }
  484. /** @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 });
  485. /** @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: [
  486. {
  487. provide: NG_VALUE_ACCESSOR,
  488. useExisting: forwardRef((() => InvisibleReCaptchaComponent)),
  489. multi: true,
  490. }
  491. ], viewQueries: [{ propertyName: "captchaWrapperElem", first: true, predicate: ["captchaWrapperElem"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: `
  492. <div #captchaWrapperElem></div>`, isInline: true });
  493. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: InvisibleReCaptchaComponent, decorators: [{
  494. type: Component,
  495. args: [{
  496. selector: 'ngx-invisible-recaptcha',
  497. template: `
  498. <div #captchaWrapperElem></div>`,
  499. providers: [
  500. {
  501. provide: NG_VALUE_ACCESSOR,
  502. useExisting: forwardRef((() => InvisibleReCaptchaComponent)),
  503. multi: true,
  504. }
  505. ]
  506. }]
  507. }], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.NgZone }, { type: i0.Injector }, { type: ScriptService }]; }, propDecorators: { theme: [{
  508. type: Input
  509. }], badge: [{
  510. type: Input
  511. }], captchaWrapperElem: [{
  512. type: ViewChild,
  513. args: ['captchaWrapperElem', { static: false }]
  514. }] } });
  515. class ReCaptcha2Component extends BaseReCaptchaComponentDirective {
  516. constructor(renderer, zone, injector, scriptService) {
  517. super(renderer, zone, injector, scriptService);
  518. this.renderer = renderer;
  519. this.zone = zone;
  520. this.injector = injector;
  521. this.scriptService = scriptService;
  522. /**
  523. * Name of the global expire callback
  524. */
  525. this.windowOnErrorCallbackProperty = 'ngx_captcha_error_callback';
  526. /**
  527. * Name of the global error callback
  528. */
  529. this.windowOnExpireCallbackProperty = 'ngx_captcha_expire_callback';
  530. /**
  531. * Theme
  532. */
  533. this.theme = 'light';
  534. /**
  535. * Size
  536. */
  537. this.size = 'normal';
  538. this.recaptchaType = ReCaptchaType.ReCaptcha2;
  539. }
  540. ngOnChanges(changes) {
  541. super.ngOnChanges(changes);
  542. }
  543. ngOnDestroy() {
  544. window[this.windowOnErrorCallbackProperty] = {};
  545. window[this.windowOnExpireCallbackProperty] = {};
  546. }
  547. captchaSpecificSetup() {
  548. this.registerCallbacks();
  549. }
  550. /**
  551. * Gets reCaptcha properties
  552. */
  553. getCaptchaProperties() {
  554. return {
  555. 'sitekey': this.siteKey,
  556. 'callback': (response) => this.zone.run(() => this.handleCallback(response)),
  557. 'expired-callback': () => this.zone.run(() => this.handleExpireCallback()),
  558. 'error-callback': () => this.zone.run(() => this.handleErrorCallback()),
  559. 'theme': this.theme,
  560. 'type': this.type,
  561. 'size': this.size,
  562. 'tabindex': this.tabIndex
  563. };
  564. }
  565. /**
  566. * Registers global callbacks
  567. */
  568. registerCallbacks() {
  569. window[this.windowOnErrorCallbackProperty] = super.handleErrorCallback.bind(this);
  570. window[this.windowOnExpireCallbackProperty] = super.handleExpireCallback.bind(this);
  571. }
  572. }
  573. /** @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 });
  574. /** @nocollapse */ ReCaptcha2Component.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.0.4", type: ReCaptcha2Component, selector: "ngx-recaptcha2", inputs: { theme: "theme", size: "size" }, providers: [
  575. {
  576. provide: NG_VALUE_ACCESSOR,
  577. useExisting: forwardRef((() => ReCaptcha2Component)),
  578. multi: true,
  579. }
  580. ], viewQueries: [{ propertyName: "captchaWrapperElem", first: true, predicate: ["captchaWrapperElem"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: `
  581. <div #captchaWrapperElem></div>`, isInline: true });
  582. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: ReCaptcha2Component, decorators: [{
  583. type: Component,
  584. args: [{
  585. selector: 'ngx-recaptcha2',
  586. template: `
  587. <div #captchaWrapperElem></div>`,
  588. providers: [
  589. {
  590. provide: NG_VALUE_ACCESSOR,
  591. useExisting: forwardRef((() => ReCaptcha2Component)),
  592. multi: true,
  593. }
  594. ]
  595. }]
  596. }], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.NgZone }, { type: i0.Injector }, { type: ScriptService }]; }, propDecorators: { theme: [{
  597. type: Input
  598. }], size: [{
  599. type: Input
  600. }], captchaWrapperElem: [{
  601. type: ViewChild,
  602. args: ['captchaWrapperElem', { static: false }]
  603. }] } });
  604. class ReCaptchaV3Service {
  605. constructor(scriptService, zone) {
  606. this.scriptService = scriptService;
  607. this.zone = zone;
  608. }
  609. /**
  610. * Executes reCaptcha v3/Enterprise with given action and passes token via callback. You need to verify
  611. * this callback in your backend to get meaningful results.
  612. *
  613. * For more information see https://developers.google.com/recaptcha/docs/v3
  614. * For enterprise see https://cloud.google.com/recaptcha-enterprise/docs
  615. *
  616. * @param siteKey Site key found in your google admin panel
  617. * @param action Action to log
  618. * @param callback Callback function to to handle token
  619. * @param config Optional configuration like useGlobalDomain to be provided
  620. * @param errorCallback Optional Callback function to handle errors
  621. */
  622. execute(siteKey, action, callback, config, errorCallback) {
  623. this.executeAsPromise(siteKey, action, config)
  624. .then(callback)
  625. .catch((error) => errorCallback ? errorCallback(error) : console.error(error));
  626. }
  627. /**
  628. * Executes reCaptcha v3/Enterprise with given action and returns token via Promise. You need to verify
  629. * this token in your backend to get meaningful results.
  630. *
  631. * For more information see https://developers.google.com/recaptcha/docs/v3
  632. * For enterprise see https://cloud.google.com/recaptcha-enterprise/docs
  633. *
  634. * @param siteKey Site key found in your google admin panel
  635. * @param action Action to log
  636. * @param config Optional configuration like useGlobalDomain to be provided
  637. */
  638. executeAsPromise(siteKey, action, config) {
  639. return new Promise((resolve, reject) => {
  640. const configuration = config || {};
  641. const onRegister = (grecaptcha) => {
  642. this.zone.runOutsideAngular(() => {
  643. try {
  644. grecaptcha
  645. .execute(siteKey, { action })
  646. .then((token) => this.zone.run(() => resolve(token)));
  647. }
  648. catch (error) {
  649. reject(error);
  650. }
  651. });
  652. };
  653. this.scriptService.registerCaptchaScript(configuration, siteKey, onRegister);
  654. });
  655. }
  656. }
  657. /** @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 });
  658. /** @nocollapse */ ReCaptchaV3Service.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: ReCaptchaV3Service, providedIn: "root" });
  659. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: ReCaptchaV3Service, decorators: [{
  660. type: Injectable,
  661. args: [{
  662. providedIn: "root",
  663. }]
  664. }], ctorParameters: function () { return [{ type: ScriptService }, { type: i0.NgZone }]; } });
  665. class NgxCaptchaModule {
  666. }
  667. /** @nocollapse */ NgxCaptchaModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: NgxCaptchaModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
  668. /** @nocollapse */ NgxCaptchaModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.0.4", ngImport: i0, type: NgxCaptchaModule, declarations: [ReCaptcha2Component,
  669. InvisibleReCaptchaComponent], imports: [CommonModule], exports: [ReCaptcha2Component,
  670. InvisibleReCaptchaComponent] });
  671. /** @nocollapse */ NgxCaptchaModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: NgxCaptchaModule, providers: [
  672. ScriptService,
  673. ReCaptchaV3Service
  674. ], imports: [CommonModule] });
  675. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: NgxCaptchaModule, decorators: [{
  676. type: NgModule,
  677. args: [{
  678. imports: [
  679. CommonModule
  680. ],
  681. declarations: [
  682. ReCaptcha2Component,
  683. InvisibleReCaptchaComponent
  684. ],
  685. providers: [
  686. ScriptService,
  687. ReCaptchaV3Service
  688. ],
  689. exports: [
  690. ReCaptcha2Component,
  691. InvisibleReCaptchaComponent
  692. ]
  693. }]
  694. }] });
  695. /*
  696. * Public API
  697. */
  698. /**
  699. * Generated bundle index. Do not edit.
  700. */
  701. export { BaseReCaptchaComponentDirective, InvisibleReCaptchaComponent, NgxCaptchaModule, ReCaptcha2Component, ReCaptchaType, ReCaptchaV3Service, ScriptService };
  702. //# sourceMappingURL=ngx-captcha.mjs.map