Instalación de hCaptcha (sustituto de recaptcha de Google) en Angular/Angular Universal para rentabilizar tu web.

Cómo ya sabréis, es imprescindible tener en vuestros proyectos web un sistema para evitar la entrada masiva de usuarios falsos o bots automatizados. Hasta hace pocos meses, reCAPTCHA de Google (presentado en el artículo https://1938.com.es/ejemplo-captcha) era el sistema más utilizados para evitar este tipo de ataques. Sin embargo, poco a poco, hCAPTCHA ha ido captando mercado hasta llegar a super un 20% de cuota de mercado a través de sus sistemas más privados y su sistema de monetización.

En un reciente anuncio, hCAPTCHA indica que es el servicio independiente más grande de CAPTCHA de Internet. Para ello comentan estar operativos en un 15% de Internet, cuota que presumen haber quitado en gran parte a Google y su ya mítico reCAPTCHA. Un gran impulso para aumentar su cuota de mercado fue sin duda alguna la integración en Cloudflare. El gigante de Internet Cloudflare decidió dejar reCAPTCHA de Google en abril de este año y apostar por hCAPTCHA.

En este articulo vamos a enseñar a instalar el siguiente hCAPTCHA, paso a paso, en vuestro proyecto angular universal y poder obtener un ingreso extra en vuestro proyecto.

Os dejo el repositorio https://github.com/al118345/ejemplo-hcaptcha-en-angular-universal para su consulta y el siguiente video explicativo:

Beneficios de hCaptcha

La siguiente tabla muestra un resumen de las ventajas de hCaptcha sobre reCaptcha.
  • Gratuito: hCaptcha es gratuito al completo. Por otra parte, reCaptcha de Google también, excepto si tienes un volumen elevado de visitas.
  • Obtienes beneficios:Los CAPTCHAS solucionados mediante hCAPTCHA son tareas que requieren personas para ser resultas. Por cada vez que se resuelve una CAPTCHA, hCAPTCHA otorga al administrador un token. Dichos tokens se pueden convertir en dinero o ser donados a una organización sin ánimo de lucro.
  • Ayudas a implementar nuevos algoritmos: Resolver CAPTCHAS ayuda a entrenar algoritmos para que entiendan mejor el comportamiento humano o mejorar su reconocimiento de patrones.
simbolo hcaptcha

Alta en hCaptcha.

En este articulo partimos con la premisa de que posees una cuenta de Gmail.

El primer paso es darse de alta en la url https://hCaptcha.com/?r=335d4419fb51. Una vez accedamos y estemos logueados en la cuenta de Gmail aparecerá la siguiente vista.

simbolo hcaptcha

O desde la vista de sitios

simbolo hcaptcha

Una vez hemos accedido, debemos rellenar el formulario con el dominio dónde lo vamos a ejecutar. A continuación os dejo el ejemplo que hemos aplicado para la web 1938.com.es
simbolo hcaptcha
Rellenado el formulario aparecerá la siguiente pantalla con la información acerca de la clave para utilizar el servicio.

Si presionamos encima de configuraciones podremos consultar la clave publica para utilizarla en nuestro proyecto. Presionar este botón nos llevará a la siguiente pestaña:

También necesitamos la clave privada, es decir, debemos acceder a la pestaña de configuración para obtenerla cómo se muestra a continuación.

Por último, la clave privada en la pestaña de configuración

Importante: Para las pruebas en localhost tenemos la posibilidad de usar:
  • Site Key: 10000000-ffff-ffff-ffff-000000000001
  • Secret Key: 0x0000000000000000000000000000000000000000

Instalación

Para realizar esta instalación, hay que dividir el proyecto entre un front-end y un back-end. El front realizará la interacción con el usuario y el backend se comunicará con hCaptcha.

Desde Angular realizaremos la instalación del paquete ng-hcaptcha con el siguiente comando:
npm install --save --force ng-hcaptcha 

Además crearemos el siguiente servicio para comunicarse con la api de Python.

ng generate service service/hcaptcha
import {Inject, Injectable, PLATFORM_ID} from '@angular/core';
import {isPlatformBrowser} from '@angular/common';
@Injectable({
  providedIn: 'root'
})
export class HcaptchaService {

  public isBrowser  = false;

  constructor(@Inject(PLATFORM_ID) private platformId: Object) {
    if (isPlatformBrowser(platformId)) {
      this.isBrowser = true;
    }
  }

  getToken(token: string): string {
    if  (this.isBrowser == true){
      const xhr = new XMLHttpRequest();
      xhr.open('POST', 'urldestino' + token, false);
      xhr.send();
      const aux = JSON.parse(xhr.responseText);
      return  xhr.responseText ;
    } else {
      return 'false'
    }
  }

}

Importamos el módulo a nuestra app con el siguiente código:

import {NgHcaptchaModule} from 'ng-hcaptcha';

@NgModule({
  declarations: [],
  imports: [
   NgHcaptchaModule.forRoot({
      //modificar con tu llave
      siteKey: '10000000-ffff-ffff-ffff-000000000001',
      languageCode: 'es' // optional, will default to browser language
    })

  ],
  providers: [
   ]
})
Y añadiremos la funcionalidad en el componente.html:
<div *ngIf="robot == true">
    <p>Eres un robot</p>
</div>
<div *ngIf="robot == false">
    <p>No eres un robot</p>
</div>
<div *ngIf="expirado == true">
  <p>Captcha expirado. Recarga la página</p>
</div>
<ng-hcaptcha (verify)="onVerify($event)"
                   (expired)="onExpired($event)"
                   (error)="onError($event)">
</ng-hcaptcha>
Y en el componente.ts:
public robot: boolean;
public expirado: boolean;

constructor(public captchaSerice: HcaptchaService) {
    this.robot = true;
    this.expirado = false;
}

onVerify(token: string) {
    const auxiliar = this.captchaSerice.getToken(token)
    if (auxiliar.includes('true')) {
      this.robot = false;
    }
}
onExpired(response: any) {
    alert('Se ha expirado el tiempo para rellenar el sistema de seguridad. Recarga la página.');
    this.expirado=true;
}

onError(error: any) {
    alert('Tenemos un probelma, creemos que eres un robot.');
    this.robot = true;
    // An error occured during the verification process.
}

Por último, modificamos la api para recibir la petición del front-end creando la siguiente ruta en el proyecto https://github.com/al118345/envio_email_api_python
'''
Función destinada a realizar una verificación de hCaptcha
'''
class Verificar_HCaptcha(Resource):
        def post(self, token):
            recaptcha_url = 'https://hcaptcha.com/siteverify'
            #modificar por vuestra clave
            recaptcha_secret_key = '0x0000000000000000000000000000000000000000'
            payload = {
                'secret': recaptcha_secret_key,
                'response': token,
                'remoteip': request.remote_addr,
            }
            response = requests.post(recaptcha_url, data=payload)
            result = response.json()
            return result.get('success', False)

local_resources = [
    (Verificar_HCaptcha, '/verificarh/<string:token>/'),
]
Para terminar, en la web https://dashboard.hcaptcha.com/overview puedes consultar una vista como la siguiente imagen dónde puedes comprobar la cantidad de ingresos que has obtenido
simbolo hcaptcha

Ejemplo en ejecución

¿Eres un robot?. Según recaptcha de hCaptcha:

Eres un robot, resuelve el Captcha

Para Angular Universal

En el caso de querer realizar una instalación en angular universal, añadid una pequeña comprobación para evitar problemas de renderización en el servidor.

Nada más empezar, para realizar una instalación correcta de Angular Universal tenéis que aplicar el siguiente comando:

ng add @nguniversal/express-engine

Si os da un error tipo

ERESOLVE unable to resolve dependency tree

No os preocupéis, toca jugar entre este comando

npm install --force @nguniversal/express-engine

Y posteriormente

ng add @nguniversal/express-engine

Estos dos últimos pasos los tenéis que aplicar tantas cómo sea necesario hasta que no aparezca un error.

Primero os comparto el código del component.ts dónde se añade el código necesario para interpretar si se reproduce en la parte del servidor o del navegador.

constructor(
               public captchaSerice: RecaptchaService, @Inject(PLATFORM_ID) private platformId,
               private _changeDetectorRef: ChangeDetectorRef) {
    this.isBrowser = isPlatformBrowser(platformId)
    this.robot = true;
    this.expirado = false;
  }
onVerify(token: string) {
    const auxiliar = this.captchaSerice.getTokenH(token)
    if (  auxiliar.includes('true') ) {
      this.robot = false;
    };
    // The verification process was successful.
    // You can verify the token on your server now.
  }

onExpired(response: any) {
    this.expirado = true;
    this.robot = true;
    // The verification expired.
  }

onError(error: any) {
    this.robot = true;
    // An error occured during the verification process.
  }

Puede ser que os aparezca un error en la linea 2 @Inject(PLATFORM_ID) private platformId tal que así:

TS7006: Parameter 'platformId' implicitly has an 'any' type.

En ese caso, añadid al fichero tsconfig.json la siguiente línea

/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
  "compilerOptions": {
    [...]
    "noImplicitAny": false,
  }
}

Y ahora se añade el código necesario en la vista (component.html) para evitar el problema del renderizado en el servidor.

<div *ngIf="robot == true">
      <p>Eres un robot</p>
</div>
<div *ngIf="robot == false">
      <p>No eres un robot</p>
 </div>
<div *ngIf="expirado == true">
      <p>Captcha expirado. Recarga la página</p>
</div>
 <div *ngIf="isBrowser">
      <ng-hcaptcha (verify)="onVerify($event)"
                   (expired)="onExpired($event)"
                   (error)="onError($event)">
      </ng-hcaptcha>
</div>