# Código abierto de OpenWAF Verify

> La parte de navegador de OpenWAF Verify, su protocolo y sus librerías de siteverify son código abierto con licencia Apache 2.0. Qué es abierto y qué no.

La parte cliente de OpenWAF Verify es código abierto con licencia Apache 2.0: [github.com/openwaf-dev/verify](https://github.com/openwaf-dev/verify). Es el código que se ejecuta en el navegador de tus visitantes, el protocolo con el que habla con el borde y las librerías con las que tu servidor comprueba los tokens.

Puedes leer qué hacen el [widget Verify](https://developers.openwaf.dev/es/waf/verify-widget/) y el [reto de navegador](https://developers.openwaf.dev/es/waf/browser-challenge/) en el navegador del visitante, compararlo con lo que sirve tu sitio y usar las librerías en lugar de escribir tus propias llamadas a siteverify.

## Qué es abierto

- **Widget de navegador** (`challengejs/`). El script `widget.js`: la caja, sus estados, la API `owafVerify` y el campo oculto `owaf-verify-response`.
- **Worker de prueba de trabajo** (`challengejs/`). El Web Worker que resuelve los acertijos SHA-256 y la alternativa que calcula en la página cuando no hay worker.
- **Página intermedia** (`challengejs/`). La plantilla HTML y el CSS de la página del [reto de navegador](https://developers.openwaf.dev/es/waf/browser-challenge/).
- **Protocolo** (`spec/`). Cómo pide el navegador un reto, envía su solución y recibe un token, y la API de [siteverify](https://developers.openwaf.dev/es/waf/siteverify/).
- **Librerías de siteverify.** Go (`siteverify/`, módulo `github.com/openwaf-dev/verify`), Node.js y TypeScript (`node/`, `@openwaf/verify`) y PHP (`php/`, paquete de Composer `openwaf/verify`).
- **Componentes.** React (`react/`, `@openwaf/verify-react`) y Vue 3 (`vue/`, `@openwaf/verify-vue`).
- **Ejemplos** (`examples/`). Aplicaciones pequeñas que funcionan: muestran el widget y comprueban el token.

## Qué no es abierto y por qué

Algunas partes siguen cerradas:

- **La puntuación de riesgo.** Cómo convierte el borde las [señales del servidor](https://developers.openwaf.dev/es/waf/verify-risk/) en una puntuación.
- **La regla de coherencia del navegador.** Cómo comprueba el borde que un navegador se comporta como el navegador que dice ser.
- **Las comprobaciones de automatización en la página.** El módulo de comprobaciones de sí o no sobre herramientas de automatización, y cómo se codifica su respuesta en cada reto.
- **Reputación y listas de amenazas.** Las listas detrás de las [listas de amenazas](https://developers.openwaf.dev/es/waf/threat-feeds/) y la reputación.
- **El interior del borde.** El proxy y cómo funcionan sus nodos.

Estas partes deciden con cuánto cuidado mira el borde una petición. Si sus reglas exactas fueran públicas, la automatización podría ajustarse para pasarlas, y cada una dejaría de servir el mismo día en que se publicara.

Lo que leen no es secreto. Los datos que trata cada parte están en [Datos tratados](https://developers.openwaf.dev/es/waf/verify-widget/#data) y en la [puntuación de riesgo](https://developers.openwaf.dev/es/waf/verify-risk/#data).

## El widget servido no es idéntico byte a byte

El widget que sirve tu borde es este código abierto más un módulo de extensión cerrado: las comprobaciones de automatización en la página.

- El módulo hace unas pocas comprobaciones de sí o no en la página.
- Su única salida es un número entero opaco que se añade a la petición con la solución.
- No lee ninguna superficie de huella digital: ni canvas, ni WebGL, ni audio, ni fuentes, ni client hints de alta entropía.

Por ese módulo, una compilación del repositorio no es idéntica byte a byte al paquete de `/__waf/challenge/v1/widget.js`. Todo lo demás de ese paquete es el código de `challengejs/`.

## Compruébalo tú mismo

No tienes que fiarte de lo que decimos. Abre una página que use Verify, como la [demo en vivo](https://developers.openwaf.dev/demo/verify/), con las herramientas para desarrolladores del navegador:

1. **Red.** Todas las peticiones del widget van al propio host de la página, bajo `/__waf/`. Nada va a otro dominio.
2. **Cookies.** El widget no pone ninguna cookie. La página del reto de navegador pone solo `__waf_pass`, después de resolver el reto.
3. **Content Security Policy.** El widget funciona con `Content-Security-Policy: default-src 'self'`, sin infracciones en la consola. La demo funciona con esa política.
4. **Código.** Lee los `widget.js` y `worker.js` servidos y compáralos con `challengejs/` en el repositorio.


## Usar las librerías

Las librerías llaman a siteverify por ti. Siguen la [referencia de siteverify](https://developers.openwaf.dev/es/waf/siteverify/) y se comportan igual en todos los lenguajes. De momento se instalan desde el repositorio de GitHub: Go y Composer desde la etiqueta `v0.1.0`, y npm desde los tarballs adjuntos a la [versión](https://github.com/openwaf-dev/verify/releases/tag/v0.1.0). Los paquetes de npm y Packagist llegarán pronto.

**Go**

```sh
go get github.com/openwaf-dev/verify/siteverify@v0.1.0
```
```go
c, err := siteverify.New(os.Getenv("OWAF_VERIFY_SECRET"))
if err != nil {
	log.Fatal(err)
}

res, err := c.Verify(r.Context(), r.FormValue("owaf-verify-response"), siteverify.Params{
	RemoteIP:       clientIP,
	ExpectedAction: "signup",
})
if err != nil || !res.Success {
	http.Error(w, "verification failed", http.StatusForbidden)
	return
}
// crear la cuenta
```
**Node**

```sh
npm install https://github.com/openwaf-dev/verify/releases/download/v0.1.0/openwaf-verify-0.1.0.tgz
```
```ts
import { SiteverifyClient } from "@openwaf/verify";

const client = new SiteverifyClient({ secret: process.env.OWAF_VERIFY_SECRET! });

const result = await client.verify(token, { remoteIp, expectedAction: "signup" });
if (!result.success) {
  // rechazar el formulario
}
```
**PHP**

```sh
composer config repositories.openwaf-verify vcs https://github.com/openwaf-dev/verify
composer require openwaf/verify:^0.1
```
```php
<?php
$client = new OpenWAF\Verify\Siteverify\Client((string) getenv('OWAF_VERIFY_SECRET'));

$result = $client->verify(
    $_POST['owaf-verify-response'] ?? '',
    remoteIp: $clientIp,
    expectedAction: 'signup',
);
if (!$result->success) {
    http_response_code(403);
    exit('Verification failed');
}
// crear la cuenta
```
**React**

```sh
npm install https://github.com/openwaf-dev/verify/releases/download/v0.1.0/openwaf-verify-react-0.1.0.tgz
```
```tsx
import { Verify } from "@openwaf/verify-react";

<form action="/signup" method="post">
  <input name="email" type="email" required />
  <Verify siteKey="owk_YOUR_SITE_KEY" action="signup" onSuccess={(token) => setToken(token)} />
  <button type="submit">Sign up</button>
</form>
```
**Vue**

```sh
npm install https://github.com/openwaf-dev/verify/releases/download/v0.1.0/openwaf-verify-vue-0.1.0.tgz
```
```html
<script setup>
import { Verify } from "@openwaf/verify-vue";
</script>

<template>
  <form action="/signup" method="post">
    <input name="email" type="email" required />
    <Verify site-key="owk_YOUR_SITE_KEY" action="signup" @success="onToken" />
    <button type="submit">Sign up</button>
  </form>
</template>
```


Los componentes de React y Vue muestran el mismo widget, así que la página tiene que servirse a través de OpenWAF.

Qué hacen las librerías de servidor:

- **Valores por defecto.** Llaman a `https://dash.openwaf.dev/v1/challenge/siteverify` con un tiempo de espera de 10 segundos. Puedes apuntarlas a `https://<tu host>/__waf/challenge/siteverify`.
- **Sin petición cuando no puede salir bien.** Un token vacío devuelve `missing-input-response` y un token de más de 2048 bytes devuelve `invalid-input-response`, sin llamar a siteverify.
- **Nombre de host y acción.** Si indicas el nombre de host o la acción que esperas y el token no coincide, la respuesta es un fallo con `hostname-mismatch` o `action-mismatch`. Estos dos códigos los pone la librería, no siteverify.
- **Respuestas y errores.** Toda respuesta de siteverify, incluidas `400`, `405` y `429` (con su `Retry-After`), vuelve como resultado. Un tiempo de espera agotado, un fallo de red, otro estado HTTP o un cuerpo que no es JSON es un error: errores centinela en Go, `SiteverifyError` en Node y `SiteverifyException` en PHP, con los códigos `timeout`, `network`, `http` y `bad-response`.
- **Sin reintentos automáticos.** Para reintentar después de un tiempo de espera agotado, envía otra vez la misma [clave de idempotencia](https://developers.openwaf.dev/es/waf/siteverify/#idempotency): la segunda llamada recibe la primera respuesta en lugar de `timeout-or-duplicate`.
- **El secreto no sale en los errores.** Nunca aparece en mensajes de error, logs ni objetos impresos.

Pruébalas con las [claves de prueba](https://developers.openwaf.dev/es/waf/verify-widget/#test-keys): `ows_test_pass`, `ows_test_fail` y `ows_test_spent` funcionan sin widget.

## Licencia

Todo el repositorio tiene la [licencia Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0). Puedes usarlo, cambiarlo y redistribuirlo, también en productos comerciales.

## Contribuir

Abre incidencias y pull requests en [github.com/openwaf-dev/verify](https://github.com/openwaf-dev/verify). Revisamos cada cambio. Los cambios en el código de navegador se publican con el borde, así que un cambio aceptado llega a los sitios con la siguiente versión del borde.

## Informar de una vulnerabilidad

No abras una incidencia pública. Escribe a `support@openwaf.dev` (`security@openwaf.dev` llega al mismo equipo) y sigue el [SECURITY.md](https://github.com/openwaf-dev/verify/blob/main/SECURITY.md) del repositorio.
