diff --git a/src/content/docs/de/basics/client-side-rendering.mdx b/src/content/docs/de/basics/client-side-rendering.mdx index bbcce947751bf..3708561701a69 100644 --- a/src/content/docs/de/basics/client-side-rendering.mdx +++ b/src/content/docs/de/basics/client-side-rendering.mdx @@ -160,7 +160,7 @@ Sie können beim Rendern der Procaptcha-Komponente jeden der folgenden CAPTCHA-T Verschiedene Frameworks wurden mit Procaptcha integriert. Die Dokumentation für jedes Framework finden Sie unten: -- [React Integration](/de/framework-integrations/angular-integration/) +- [React Integration](/de/framework-integrations/react-integration/) - [Vue Integration](/de/framework-integrations/vue-integration/) - [Angular Integration](/de/framework-integrations/angular-integration/) - [Svelte Integration](/de/framework-integrations/svelte-integration/) diff --git a/src/content/docs/de/basics/invisible-captcha.mdx b/src/content/docs/de/basics/invisible-captcha.mdx index 864c739944d94..e7dcc5595906a 100644 --- a/src/content/docs/de/basics/invisible-captcha.mdx +++ b/src/content/docs/de/basics/invisible-captcha.mdx @@ -11,7 +11,7 @@ Unsichtbares CAPTCHA befindet sich derzeit in der **Beta**-Phase. Funktionen und ::: :::note[Stufen-Beschränkung] -Unsichtbares CAPTCHA ist nur für Benutzer der **Pro- und Enterprise**-Stufen verfügbar. Benutzer der kostenlosen Stufe können nicht auf diese Funktion zugreifen. +Unsichtbares CAPTCHA ist nur für Benutzer der **Professional- und Enterprise**-Stufen verfügbar. Benutzer der kostenlosen Stufe können nicht auf diese Funktion zugreifen. ::: ## Übersicht @@ -219,18 +219,18 @@ const response = await fetch('https://api.prosopo.io/siteverify', { }, body: JSON.stringify({ secret: 'your_secret_key', - response: token, // Token from Procaptcha callback - remoteip: userIP // Optional + token: token, // Token from Procaptcha callback + ip: userIP // Optional }) }); const result = await response.json(); -if (result.success) { +if (result.verified) { // Procaptcha verified successfully console.log('Verification successful'); } else { // Verification failed - console.log('Verification failed:', result['error-codes']); + console.log('Verification failed:', result.status); } ``` diff --git a/src/content/docs/de/basics/server-side-verification.mdx b/src/content/docs/de/basics/server-side-verification.mdx index 28433e7dcc896..bffecdca825f4 100644 --- a/src/content/docs/de/basics/server-side-verification.mdx +++ b/src/content/docs/de/basics/server-side-verification.mdx @@ -95,7 +95,8 @@ async function verifyToken(token) { headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ secret: 'your_secret_key', token }), }); - return response.json().verified || false; // Return verified field, default to false + const data = await response.json(); + return data.verified || false; // Return verified field, default to false } ``` @@ -193,7 +194,8 @@ Um eine Benutzerantwort mit JavaScript / TypeScript zu verifizieren, importieren die `procaptcha-response` POST-Daten. Typen können aus `@prosopo/types` importiert werden. ```typescript -import {ProsopoServer} from '@prosopo/server' +import {ProsopoServer, getServerConfig} from '@prosopo/server' +import {getPair} from '@prosopo/keyring' import {ApiParams} from '@prosopo/types' ... @@ -204,10 +206,13 @@ const payload = JSON.parse(event.body) const procaptchaResponse = payload[ApiParams.procaptchaResponse] // initialise the `ProsopoServer` class -const prosopoServer = new ProsopoServer(config) +const config = getServerConfig() +const pair = getPair(process.env.PROSOPO_SITE_PRIVATE_KEY, config.account.address) +const prosopoServer = new ProsopoServer(config, pair) // check if the captcha response is verified -if (await prosopoServer.isVerified(procaptchaResponse)) { +const result = await prosopoServer.isVerified(procaptchaResponse) +if (result.verified) { // perform CAPTCHA protected action } ``` diff --git a/src/content/docs/de/welcome/index.mdx b/src/content/docs/de/welcome/index.mdx index ea65d9266077d..11ae07c2ee25b 100644 --- a/src/content/docs/de/welcome/index.mdx +++ b/src/content/docs/de/welcome/index.mdx @@ -26,7 +26,7 @@ Sie können ein vollständiges Beispiel zur Implementierung von Procaptcha in ei Verschiedene Frameworks wurden mit Procaptcha integriert. Die Dokumentation für jedes Framework finden Sie unten: -- [React Integration](/de/framework-integrations/angular-integration/) +- [React Integration](/de/framework-integrations/react-integration/) - [Vue Integration](/de/framework-integrations/vue-integration/) - [Angular Integration](/de/framework-integrations/angular-integration/) - [Svelte Integration](/de/framework-integrations/svelte-integration/) diff --git a/src/content/docs/en/advanced/access-control-rules.mdx b/src/content/docs/en/advanced/access-control-rules.mdx index 3d28033c5549f..93f4bdc505098 100644 --- a/src/content/docs/en/advanced/access-control-rules.mdx +++ b/src/content/docs/en/advanced/access-control-rules.mdx @@ -94,6 +94,16 @@ Match requests from specific countries using ISO 3166-1 alpha-2 country codes. **Use case:** Apply stricter or more lenient policies for specific geographic regions. +#### ASN + +Match the Autonomous System Number (ASN) of the IP's network. Useful for blocking or restricting traffic from a specific hosting provider, ISP, or VPN/proxy network without enumerating every IP they own. + +**Format:** Numeric AS number (e.g., `14061`, `32934`) + +**Examples:** `14061` (DigitalOcean), `32934` (Meta), `13335` (Cloudflare) + +**Use case:** Restrict or block traffic from cloud hosting networks frequently used by bots, or apply policies to whole ISPs in response to abuse patterns. + ### Operators Currently, only the **equals** operator is supported. The condition matches when the field value exactly equals the specified value. @@ -296,6 +306,16 @@ JA4 Hash equals "t13d1516h2_8daaf6152771_a278895b5b6a" Policy: Block ``` +### ASN-Based Blocking + +Restrict traffic from a whole hosting provider or ISP by AS number: + +```typescript +// Restrict traffic from a cloud hosting ASN +ASN equals "14061" +Policy: Proof of Work, difficulty 5 +``` + ## Considerations ### Account-Wide Scope diff --git a/src/content/docs/en/advanced/traffic-filter.mdx b/src/content/docs/en/advanced/traffic-filter.mdx index 1b39269736d0e..f100bdda7da95 100644 --- a/src/content/docs/en/advanced/traffic-filter.mdx +++ b/src/content/docs/en/advanced/traffic-filter.mdx @@ -36,7 +36,9 @@ Traffic filter checks run before other verification logic (captcha correctness, ## Providing the IP Address -Traffic filters require the user's IP address. Pass it in the `ip` field when calling the server-side verification endpoint: +Traffic filters always run. By default they evaluate the IP recorded when the user initiated the captcha session (the browser's IP at session-start time, captured by the provider when the widget first contacted it). + +If the end user's IP may have changed between solving the captcha and your server calling `/verify` (e.g. they moved networks), pass the current IP in the optional `ip` field. The provider then re-resolves IP info against that "now" IP and runs the filters on the fresh result: ```json { @@ -48,8 +50,6 @@ Traffic filters require the user's IP address. Pass it in the `ip` field when ca See the [Server-side Verification](/en/basics/server-side-verification/#optional-ip-address) docs for details. -If no IP address is provided, traffic filters are still evaluated but only the abusive-network filter will fire (using the connecting IP from the request itself). - ## Filter Details ### VPN diff --git a/src/content/docs/en/basics/client-side-rendering.mdx b/src/content/docs/en/basics/client-side-rendering.mdx index 97f1aeed19dd3..ebea4a0bea3f5 100644 --- a/src/content/docs/en/basics/client-side-rendering.mdx +++ b/src/content/docs/en/basics/client-side-rendering.mdx @@ -160,7 +160,7 @@ You can choose to implement any of the following types of captcha when rendering Various frameworks have been integrated with Procaptcha. You can find the documentation for each framework below: -- [React Integration](/en/framework-integrations/angular-integration/) +- [React Integration](/en/framework-integrations/react-integration/) - [Vue Integration](/en/framework-integrations/vue-integration/) - [Angular Integration](/en/framework-integrations/angular-integration/) - [Svelte Integration](/en/framework-integrations/svelte-integration/) diff --git a/src/content/docs/en/basics/invisible-captcha.mdx b/src/content/docs/en/basics/invisible-captcha.mdx index c7097e248ce88..2c26f8c33d187 100644 --- a/src/content/docs/en/basics/invisible-captcha.mdx +++ b/src/content/docs/en/basics/invisible-captcha.mdx @@ -11,7 +11,7 @@ Invisible CAPTCHA is currently in **beta**. Features and behavior may change in ::: :::note[Tier Restriction] -Invisible CAPTCHA is only available for **Pro and Enterprise** tier users. Free tier users cannot access this feature. +Invisible CAPTCHA is only available for **Professional and Enterprise** tier users. Free tier users cannot access this feature. ::: ## Overview @@ -219,18 +219,18 @@ const response = await fetch('https://api.prosopo.io/siteverify', { }, body: JSON.stringify({ secret: 'your_secret_key', - response: token, // Token from Procaptcha callback - remoteip: userIP // Optional + token: token, // Token from Procaptcha callback + ip: userIP // Optional }) }); const result = await response.json(); -if (result.success) { +if (result.verified) { // Procaptcha verified successfully console.log('Verification successful'); } else { // Verification failed - console.log('Verification failed:', result['error-codes']); + console.log('Verification failed:', result.status); } ``` diff --git a/src/content/docs/en/basics/server-side-verification.mdx b/src/content/docs/en/basics/server-side-verification.mdx index 8e92aeb43dd4e..6b66af45462dd 100644 --- a/src/content/docs/en/basics/server-side-verification.mdx +++ b/src/content/docs/en/basics/server-side-verification.mdx @@ -112,7 +112,8 @@ on the request. This is optional, but recommended for better accuracy. To do thi headers: {'Content-Type': 'application/json'}, body: JSON.stringify({secret: 'your_secret_key', token}), }); - return response.json().verified || false; // Return verified field, default to false + const data = await response.json(); + return data.verified || false; // Return verified field, default to false } ``` @@ -210,7 +211,8 @@ To verify a user's response using JavaScript / TypeScript, simpy import the `ver the `procaptcha-response` POST data. Types can be imported from `@prosopo/types`. ```typescript -import {ProsopoServer} from '@prosopo/server' +import {ProsopoServer, getServerConfig} from '@prosopo/server' +import {getPair} from '@prosopo/keyring' import {ApiParams} from '@prosopo/types' ... @@ -221,10 +223,13 @@ const payload = JSON.parse(event.body) const procaptchaResponse = payload[ApiParams.procaptchaResponse] // initialise the `ProsopoServer` class -const prosopoServer = new ProsopoServer(config) +const config = getServerConfig() +const pair = getPair(process.env.PROSOPO_SITE_PRIVATE_KEY, config.account.address) +const prosopoServer = new ProsopoServer(config, pair) // check if the captcha response is verified -if (await prosopoServer.isVerified(procaptchaResponse)) { +const result = await prosopoServer.isVerified(procaptchaResponse) +if (result.verified) { // perform CAPTCHA protected action } ``` diff --git a/src/content/docs/en/protect-edge/cloudflare-worker.mdx b/src/content/docs/en/protect-edge/cloudflare-worker.mdx new file mode 100644 index 0000000000000..7fe65cd89dc62 --- /dev/null +++ b/src/content/docs/en/protect-edge/cloudflare-worker.mdx @@ -0,0 +1,151 @@ +--- +title: Cloudflare Worker +description: Deploy the Prosopo Protect Cloudflare Worker in front of your origin so proxy, VPN, datacenter and Tor traffic is blocked at Cloudflare's edge. +i18nReady: true +--- + +The Prosopo Protect Cloudflare Worker sits in front of your origin and runs Protect's decision on every request. On `allow` it forwards to your origin; on `block` / `challenge` it returns immediately with a branded interstitial (or JSON error for API calls), no origin fetch. + +## What you get + +A single JavaScript file, `worker.js`, delivered per site and per environment. It's self-contained — no dependencies, ~50 KB. + +## Prerequisites + +- A Cloudflare account with **Workers Scripts: Read + Edit** on the API token you'll use. +- [`wrangler`](https://developers.cloudflare.com/workers/wrangler/install-and-update/) installed locally (`npm i -g wrangler`). +- A Cloudflare zone (for a custom domain) or a workers.dev subdomain (fine for testing). +- A CNAME record for your Protect API hostname — see the next section. + +## DNS: point your Protect subdomain at Prosopo + +The worker talks to your Protect API over HTTPS at a hostname you own — typically `protect.`. Create a CNAME record on your DNS pointing that hostname at Prosopo: + +``` +protect. CNAME protect.prosopo.io +``` + +Then enter the same hostname (e.g. `protect.example.com`) in the **CNAME** field of your site's Protect settings on your [Prosopo dashboard](https://portal.prosopo.io/). Prosopo uses this to route TLS requests arriving at that SNI to your site's configuration. + +Set `BUMBLEBEE_URL` in `wrangler.toml` (below) to `https://protect.` — the CNAMEd hostname, not `protect.prosopo.io` directly. TLS certificate handling is managed by Prosopo automatically for the CNAMEd hostname. + +Verify the DNS is live before deploying the worker: + +```bash +dig protect. +# should show a CNAME to protect.prosopo.io and an A record. +``` + +**Do not use NS delegation.** Only a CNAME record is supported; NS would delegate the whole subdomain to Prosopo's nameservers, which isn't the model. + +## Deploy + +Cloudflare Workers is configured by a small `wrangler.toml` alongside the bundle. Create one next to `worker.js`: + +```toml +name = "prosopo-protect" +main = "worker.js" +compatibility_date = "2025-01-15" +compatibility_flags = ["nodejs_compat"] + +# Optional: bind static assets you want the worker to serve when a +# request is allowed. Delete this block if your worker fronts an +# upstream origin instead. +[assets] +directory = "./public" +binding = "ASSETS" +run_worker_first = true + +[vars] +BUMBLEBEE_URL = "https://protect.prosopo.io" +``` + +Then deploy: + +```bash +export CLOUDFLARE_API_TOKEN= + +# 1. Push the authentication token as a wrangler secret (once per environment) +echo "" | wrangler secret put CLIENT_JWT + +# 2. Deploy +wrangler deploy +``` + +The worker is now live at `https://..workers.dev`. To attach to a custom hostname, add a **Route** in `wrangler.toml` (e.g. `route = "example.com/*"`) and redeploy. + +Your account manager will let you know when a new bundle is available. Replace `worker.js` and re-run `wrangler deploy`. The secret persists across deploys. + +## Verify + +```bash +WORKER=https://your-worker.workers.dev + +# HTML — should serve your origin (200) +curl -sD - -H "Accept: text/html" -H "User-Agent: Mozilla/5.0" "$WORKER/" | head + +# JSON, no cookie — should 401 with no-session status +curl -sD - -H "Accept: application/json" "$WORKER/api/anything" | head +# HTTP/2 401 +# x-prosopo-status: no-session +# x-prosopo-request-id: + +# From a proxy or VPN (only if you've enabled proxy/VPN blocking on +# your Prosopo dashboard — see the next section) — should 403 with +# the branded interstitial +curl -sD - -H "Accept: text/html" -x http://your-proxy:port "$WORKER/" | head +# HTTP/2 403 +# x-prosopo-decision: block +``` + +`X-Prosopo-Request-Id` is echoed on every response and written to Protect's verdict audit log — grep from a support ticket straight to the verdict. + +## What the worker protects + +The worker runs Protect logic on every request before serving anything. You can point it at: + +- **Static assets** bound via `[assets]` in `wrangler.toml` (as in the example above). Set `run_worker_first = true` so the worker runs before Cloudflare's cache — without this, static files are served directly and Protect never sees the request. +- **An upstream origin** — swap the assets binding for a `fetch(rewrittenUrl, request)` against your upstream, and set the origin host in `wrangler.toml`. The Protect decision above the fetch is unchanged. + +## Configuring proxy, VPN and datacenter blocking + +Blocking policy lives on your [Prosopo dashboard](https://portal.prosopo.io/), not in the bundle. Two independent rule sources feed the no-cookie edge path: + +- **Site settings** — recognised IP categories: `tor`, `datacenter`, `proxy`, `vpn`, `abuser`, `mobile`, `crawler`. Configure per-category verdicts (`allow` / `challenge` / `block`). +- **Tiered access rules** — support the full rule set: IP CIDR, ASN, IP category, country, User-Agent substring, JA4 TLS fingerprint. Rules can be scoped to your site or applied globally by Prosopo. + +Either source firing blocks the request at the edge. When both match, the more restrictive verdict wins (`Block > Challenge > Allow`). Policy changes take effect on the next request — no redeploy needed. + +## Rotating credentials + +The authentication token is stored as a wrangler secret, so rotating it is a one-liner and doesn't require a redeploy: + +```bash +echo "" | wrangler secret put CLIENT_JWT +``` + +The next request picks up the new value. + +## Performance + +Protect's API calls from a Cloudflare Worker typically return in under 40 ms (under 2 ms for cached lookups) and are budgeted to a 500 ms hard timeout, with fail-open on transient errors. On an `allow` verdict the request continues to your origin as normal; on `block` or `challenge` the worker returns immediately without an origin fetch, so protected requests are strictly faster than unprotected ones for the blocked path. + +## TLS caveats + +Cloudflare Workers doesn't expose a way to skip TLS verification on outbound fetches. If the Protect API URL you're configured with has an invalid or expired certificate, `fetch` returns HTTP 526 and Protect can't be reached. Point `BUMBLEBEE_URL` at a hostname with a valid certificate. + +## Live logs + +While debugging a deploy, `wrangler tail` streams request-by-request logs from the deployed worker: + +```bash +wrangler tail --format=pretty +``` + +## Troubleshooting + +- **`wrangler deploy` returns `Authentication error [code: 10000]`** — the token lacks **Workers Scripts: Read + Edit**. "Edit" alone isn't enough; wrangler needs both. +- **Bundle deploys but every request 401s** — the `CLIENT_JWT` secret isn't set or has expired. Re-run `wrangler secret put CLIENT_JWT` and check `wrangler secret list`. +- **HTTP 526 in `wrangler tail`** — the Protect API host's certificate is invalid or expired; see [TLS caveats](#tls-caveats). +- **HTML `Access Denied` served instead of JSON on API paths** — the endpoint's declared content type is HTML. Update the site's `defaultPathType` (or add an endpoint rule) on your Prosopo dashboard. +- **`Unknown site` in logs** — your site isn't registered with Protect. Check your dashboard or contact your account manager. diff --git a/src/content/docs/en/protect-edge/index.mdx b/src/content/docs/en/protect-edge/index.mdx new file mode 100644 index 0000000000000..7ffa797cb268c --- /dev/null +++ b/src/content/docs/en/protect-edge/index.mdx @@ -0,0 +1,34 @@ +--- +title: Prosopo Protect at the Edge +description: Deploy Prosopo Protect in front of your site with a Cloudflare Worker or AWS Lambda@Edge. Verdict lookups run at your CDN's edge so bots are blocked before they reach your origin. +i18nReady: true +--- + +Prosopo Protect can run at the edge of your CDN so blocked and challenged requests never reach your origin. Two integrations are supported today: + +- **[Cloudflare Workers](/protect-edge/cloudflare-worker)** — deploy alongside your Cloudflare zone. +- **[AWS Lambda@Edge](/protect-edge/lambda-edge)** — deploy in front of a CloudFront distribution. + +Both integrations enforce the same policy: they consult the Prosopo Protect API on every incoming request and act on the returned verdict before it reaches your origin. + +## How it works + +On every request that hits your CDN: + +1. **If the request has a `prosopo_session` cookie** the edge fetches the verdict for the session's token from the Prosopo Protect API. `allow` passes through to your origin; `block` returns a branded interstitial (or JSON error for API calls) with no origin fetch; `challenge` serves a captcha interstitial. +2. **If the request has no cookie** the edge asks Protect what to do. Protect evaluates your access-rule set (IP CIDR, ASN, IP category, country, User-Agent, JA4 TLS fingerprint) against the request. Rule matches return `block` or `challenge`; if no rule matches and the path is an HTML SPA shell, the edge lets it through so the Protect script can create a session. + +The blocked-response HTML and challenge interstitial are branded per site via your Prosopo dashboard: logo, colour palette, typography, and message strings all sanitised and rendered server-side by the edge. + +## Correlation + +Every edge request is stamped with an `X-Prosopo-Request-Id` header that's echoed on the response and written to the verdict audit log. From a support ticket you can grep straight to the verdict that fired. + +## What's next + +Pick your platform: + +- **[Cloudflare Worker](/protect-edge/cloudflare-worker)** — install, configure, deploy, verify. +- **[AWS Lambda@Edge](/protect-edge/lambda-edge)** — same policy, deployed in front of CloudFront. + +Before you deploy, your Prosopo site must be registered with the Protect service. Site registration is handled from your [Prosopo dashboard](https://portal.prosopo.io/) or by your Prosopo account manager — you will need the site's SS58 key (e.g. `5HSuC1s…`) and a `CLIENT_JWT` signed by the site's key to authenticate the edge to the Protect API. diff --git a/src/content/docs/en/protect-edge/lambda-edge.mdx b/src/content/docs/en/protect-edge/lambda-edge.mdx new file mode 100644 index 0000000000000..397a3a0487a15 --- /dev/null +++ b/src/content/docs/en/protect-edge/lambda-edge.mdx @@ -0,0 +1,152 @@ +--- +title: AWS Lambda@Edge +description: Deploy the Prosopo Protect Lambda@Edge bundle in front of a CloudFront distribution so bots and abusive traffic are blocked before they reach your origin. +i18nReady: true +--- + +The Prosopo Protect Lambda@Edge bundle runs on Amazon CloudFront's viewer-request trigger. It executes Protect's decision on every request and either forwards the request to your origin (`allow`), blocks it with a branded interstitial (`block`), or serves a captcha challenge (`challenge`). + +## What you get + +A single JavaScript file, `lambda-edge.js`, delivered per site and per environment. It's self-contained — no dependencies, no configuration, ~100 KB. + +## Prerequisites + +- An AWS account with permission to create Lambda functions in **`us-east-1`** (Lambda@Edge functions must live there), publish versions of that function, and attach viewer-request triggers to your CloudFront distributions. +- A CloudFront distribution serving your origin. +- The [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) or the AWS Console. +- A CNAME record for your Protect API hostname — see the next section. + +## DNS: point your Protect subdomain at Prosopo + +The bundle talks to your Protect API over HTTPS at a hostname you own — typically `protect.`. Create a CNAME record on your DNS pointing that hostname at Prosopo: + +``` +protect. CNAME protect.prosopo.io +``` + +Then enter the same hostname (e.g. `protect.example.com`) in the **CNAME** field of your site's Protect settings on your [Prosopo dashboard](https://portal.prosopo.io/). Prosopo uses this to route TLS requests arriving at that SNI to your site's configuration. + +The bundle you receive from Prosopo is built against your CNAMEd hostname — you don't need to configure the URL yourself. If you rotate the CNAMEd hostname, request a fresh bundle. TLS certificate handling is managed by Prosopo automatically for the CNAMEd hostname. + +Verify the DNS is live before deploying the bundle: + +```bash +dig protect. +# should show a CNAME to protect.prosopo.io and an A record. +``` + +**Do not use NS delegation.** Only a CNAME record is supported; NS would delegate the whole subdomain to Prosopo's nameservers, which isn't the model. + +## Deploy + +Upload the bundle to Lambda, publish a version, and attach the versioned ARN to the CloudFront behaviour you want to protect. + +```bash +zip lambda-edge.zip lambda-edge.js + +# First deploy: create the function +aws lambda create-function \ + --region us-east-1 \ + --function-name prosopo-protect-viewer-request \ + --runtime nodejs22.x \ + --handler lambda-edge.handler \ + --memory-size 256 \ + --timeout 5 \ + --role arn:aws:iam:::role/ \ + --zip-file fileb://lambda-edge.zip + +# Every deploy after that: update the code +aws lambda update-function-code \ + --region us-east-1 \ + --function-name prosopo-protect-viewer-request \ + --zip-file fileb://lambda-edge.zip + +# Publish a version — Lambda@Edge only accepts versioned ARNs +aws lambda publish-version \ + --region us-east-1 \ + --function-name prosopo-protect-viewer-request +``` + +The `publish-version` response includes a `FunctionArn` ending in `:`. In your CloudFront distribution's **Behaviors** tab, edit the behaviour you want to protect and add a **Function association**: + +- **Event type**: Viewer request +- **Function type**: Lambda@Edge +- **Function ARN**: the versioned ARN from `publish-version`. + +CloudFront propagates to every edge location in 2–5 minutes. Repeat this attach step for each behaviour that should be protected. + +Your account manager will let you know when a new bundle is available. Run `update-function-code` + `publish-version` and point the behaviour at the new versioned ARN — CloudFront won't pick up `$LATEST`. + +### Execution role + +The function's role needs both `lambda.amazonaws.com` and `edgelambda.amazonaws.com` as trusted principals, plus the `AWSLambdaBasicExecutionRole` managed policy for CloudWatch Logs: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Service": ["lambda.amazonaws.com", "edgelambda.amazonaws.com"] + }, + "Action": "sts:AssumeRole" + } + ] +} +``` + +## Verify + +Once the trigger is attached and CloudFront has propagated, test through the distribution's domain. + +```bash +DIST=https://your-distribution.cloudfront.net + +# HTML — should serve your origin (200) +curl -sD - -H "Accept: text/html" -H "User-Agent: Mozilla/5.0" "$DIST/" | head + +# JSON, no cookie — should 401 with no-session status +curl -sD - -H "Accept: application/json" "$DIST/api/anything" | head +# HTTP/2 401 +# x-prosopo-status: no-session +# x-prosopo-request-id: + +# From a proxy or VPN (only if you've enabled proxy/VPN blocking on +# your Prosopo dashboard — see the next section) — should 403 with +# the branded interstitial +curl -sD - -H "Accept: text/html" -x http://your-proxy:port "$DIST/" | head +# HTTP/2 403 +# x-prosopo-decision: block +``` + +`X-Prosopo-Request-Id` is echoed on every response and written to Protect's verdict audit log — grep from a support ticket straight to the verdict. CloudFront's own `x-amz-cf-id` is the default request ID, so the same value shows up in CloudFront access logs and Protect's audit log. + +## Configuring proxy, VPN and datacenter blocking + +Blocking policy lives on your [Prosopo dashboard](https://portal.prosopo.io/), not in the bundle. Two independent rule sources feed the no-cookie edge path: + +- **Site settings** — recognised IP categories: `tor`, `datacenter`, `proxy`, `vpn`, `abuser`, `mobile`, `crawler`. Configure per-category verdicts (`allow` / `challenge` / `block`). +- **Tiered access rules** — support the full rule set: IP CIDR, ASN, IP category, country, User-Agent substring, JA4 TLS fingerprint. Rules can be scoped to your site or applied globally by Prosopo. + +Either source firing blocks the request at the edge. When both match, the more restrictive verdict wins (`Block > Challenge > Allow`). Policy changes take effect on the next request — no redeploy needed. + +## Constraints + +- **Region**: functions must be created in `us-east-1`. +- **Memory**: 256 MB recommended. Higher tiers cost more but give proportionally more CPU. +- **Time**: the viewer-request handler is capped at 5 seconds. Protect's API calls typically return in under 40 ms (under 2 ms for cached lookups) and are budgeted to a 500 ms hard timeout, with fail-open on transient errors. +- **CloudWatch logs**: written to the region *closest to the viewer that served the request*, not `us-east-1`. Check the matching region when debugging. + +## Rotating credentials + +Each bundle is scoped to a specific site's authentication token. Rotating the token means requesting a fresh bundle from Prosopo and redeploying it via the [Deploy](#deploy) flow. The old bundle keeps working until you swap the ARN on your CloudFront behaviour. + +## Troubleshooting + +- **CloudFront returns 502** — the function threw an unhandled exception. Check CloudWatch Logs in the region that served the request (Lambda@Edge writes logs region-locally). +- **Requests return 401 with an internal-error body** — the bundle's authentication token is stale or invalid. Request a fresh bundle from Prosopo and redeploy. +- **CloudFront won't accept the ARN** — Lambda@Edge requires a *published version* ARN (ending in `:1`, `:2`, …). `$LATEST` isn't accepted. +- **Verdict lookups time out in logs** — Protect is unreachable or slow. The function fails open so requests still reach your origin, but investigate. +- **`Unknown site` in logs** — your site isn't registered with Protect. Check your dashboard or contact your account manager. diff --git a/src/content/docs/en/welcome/index.mdx b/src/content/docs/en/welcome/index.mdx index 59efd0ee1061b..ebb8fc141ee20 100644 --- a/src/content/docs/en/welcome/index.mdx +++ b/src/content/docs/en/welcome/index.mdx @@ -30,7 +30,7 @@ of how to run the examples are in the documentation at the previous links. Various frameworks have been integrated with Procaptcha. You can find the documentation for each framework below: -- [React Integration](/en/framework-integrations/angular-integration/) +- [React Integration](/en/framework-integrations/react-integration/) - [Vue Integration](/en/framework-integrations/vue-integration/) - [Angular Integration](/en/framework-integrations/angular-integration/) - [Svelte Integration](/en/framework-integrations/svelte-integration/) diff --git a/src/content/docs/es/basics/client-side-rendering.mdx b/src/content/docs/es/basics/client-side-rendering.mdx index 867688d17d8f0..e4e3be8a7228a 100644 --- a/src/content/docs/es/basics/client-side-rendering.mdx +++ b/src/content/docs/es/basics/client-side-rendering.mdx @@ -148,7 +148,7 @@ Puede elegir implementar cualquiera de los siguientes tipos de captcha al render Varios frameworks se han integrado con Procaptcha. Puede encontrar la documentación para cada framework a continuación: -- [Integración con React](/es/framework-integrations/angular-integration/) +- [Integración con React](/es/framework-integrations/react-integration/) - [Integración con Vue](/es/framework-integrations/vue-integration/) - [Integración con Angular](/es/framework-integrations/angular-integration/) - [Integración con Svelte](/es/framework-integrations/svelte-integration/) diff --git a/src/content/docs/es/basics/invisible-captcha.mdx b/src/content/docs/es/basics/invisible-captcha.mdx index 457af622846c9..57cf9202514ed 100644 --- a/src/content/docs/es/basics/invisible-captcha.mdx +++ b/src/content/docs/es/basics/invisible-captcha.mdx @@ -11,7 +11,7 @@ CAPTCHA invisible está actualmente en **beta**. Las características y el compo ::: :::note[Restricción de nivel] -CAPTCHA invisible solo está disponible para usuarios de nivel **Pro y Enterprise**. Los usuarios del nivel gratuito no pueden acceder a esta función. +CAPTCHA invisible solo está disponible para usuarios de nivel **Professional y Enterprise**. Los usuarios del nivel gratuito no pueden acceder a esta función. ::: ## Descripción general @@ -222,18 +222,18 @@ const response = await fetch('https://api.prosopo.io/siteverify', { }, body: JSON.stringify({ secret: 'your_secret_key', - response: token, // Token from Procaptcha callback - remoteip: userIP // Optional + token: token, // Token from Procaptcha callback + ip: userIP // Optional }) }); const result = await response.json(); -if (result.success) { +if (result.verified) { // Procaptcha verified successfully console.log('Verification successful'); } else { // Verification failed - console.log('Verification failed:', result['error-codes']); + console.log('Verification failed:', result.status); } ``` diff --git a/src/content/docs/es/basics/server-side-verification.mdx b/src/content/docs/es/basics/server-side-verification.mdx index 117e1462767ca..d22c4e42793ee 100644 --- a/src/content/docs/es/basics/server-side-verification.mdx +++ b/src/content/docs/es/basics/server-side-verification.mdx @@ -90,7 +90,8 @@ async function verifyToken(token) { headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ secret: 'your_secret_key', token }), }); - return response.json().verified || false; // Return verified field, default to false + const data = await response.json(); + return data.verified || false; // Return verified field, default to false } ``` @@ -187,7 +188,8 @@ npm install @prosopo/server Para verificar la respuesta de un usuario usando JavaScript / TypeScript, simplemente importe la función `verify` desde `@prosopo/server` y pásele los datos POST `procaptcha-response`. Los tipos se pueden importar desde `@prosopo/types`. ```typescript -import {ProsopoServer} from '@prosopo/server' +import {ProsopoServer, getServerConfig} from '@prosopo/server' +import {getPair} from '@prosopo/keyring' import {ApiParams} from '@prosopo/types' ... @@ -198,10 +200,13 @@ const payload = JSON.parse(event.body) const procaptchaResponse = payload[ApiParams.procaptchaResponse] // initialise the `ProsopoServer` class -const prosopoServer = new ProsopoServer(config) +const config = getServerConfig() +const pair = getPair(process.env.PROSOPO_SITE_PRIVATE_KEY, config.account.address) +const prosopoServer = new ProsopoServer(config, pair) // check if the captcha response is verified -if (await prosopoServer.isVerified(procaptchaResponse)) { +const result = await prosopoServer.isVerified(procaptchaResponse) +if (result.verified) { // perform CAPTCHA protected action } ``` diff --git a/src/content/docs/es/welcome/index.mdx b/src/content/docs/es/welcome/index.mdx index bc8b3d532018d..72bcfb87f27e7 100644 --- a/src/content/docs/es/welcome/index.mdx +++ b/src/content/docs/es/welcome/index.mdx @@ -30,7 +30,7 @@ de cómo ejecutar los ejemplos están en la documentación en los enlaces anteri Varios frameworks se han integrado con Procaptcha. Puede encontrar la documentación para cada framework a continuación: -- [Integración con React](/es/framework-integrations/angular-integration/) +- [Integración con React](/es/framework-integrations/react-integration/) - [Integración con Vue](/es/framework-integrations/vue-integration/) - [Integración con Angular](/es/framework-integrations/angular-integration/) - [Integración con Svelte](/es/framework-integrations/svelte-integration/) diff --git a/src/content/docs/fr/basics/client-side-rendering.mdx b/src/content/docs/fr/basics/client-side-rendering.mdx index babf8996e7e2c..3859a6ea015c6 100644 --- a/src/content/docs/fr/basics/client-side-rendering.mdx +++ b/src/content/docs/fr/basics/client-side-rendering.mdx @@ -147,7 +147,7 @@ Vous pouvez choisir d'implémenter l'un des types de captcha suivants lors du re Différents frameworks ont été intégrés avec Procaptcha. Vous pouvez trouver la documentation pour chaque framework ci-dessous : -- [Intégration React](/fr/framework-integrations/angular-integration/) +- [Intégration React](/fr/framework-integrations/react-integration/) - [Intégration Vue](/fr/framework-integrations/vue-integration/) - [Intégration Angular](/fr/framework-integrations/angular-integration/) - [Intégration Svelte](/fr/framework-integrations/svelte-integration/) diff --git a/src/content/docs/fr/basics/invisible-captcha.mdx b/src/content/docs/fr/basics/invisible-captcha.mdx index e7ac87c5f3ffc..c290a4521ebef 100644 --- a/src/content/docs/fr/basics/invisible-captcha.mdx +++ b/src/content/docs/fr/basics/invisible-captcha.mdx @@ -11,7 +11,7 @@ Le CAPTCHA invisible est actuellement en **bêta**. Les fonctionnalités et le c ::: :::note[Restriction de niveau] -Le CAPTCHA invisible n'est disponible que pour les utilisateurs des niveaux **Pro et Enterprise**. Les utilisateurs du niveau gratuit ne peuvent pas accéder à cette fonctionnalité. +Le CAPTCHA invisible n'est disponible que pour les utilisateurs des niveaux **Professional et Enterprise**. Les utilisateurs du niveau gratuit ne peuvent pas accéder à cette fonctionnalité. ::: ## Aperçu @@ -219,18 +219,18 @@ const response = await fetch('https://api.prosopo.io/siteverify', { }, body: JSON.stringify({ secret: 'your_secret_key', - response: token, // Token from Procaptcha callback - remoteip: userIP // Optional + token: token, // Token from Procaptcha callback + ip: userIP // Optional }) }); const result = await response.json(); -if (result.success) { +if (result.verified) { // Procaptcha verified successfully console.log('Verification successful'); } else { // Verification failed - console.log('Verification failed:', result['error-codes']); + console.log('Verification failed:', result.status); } ``` diff --git a/src/content/docs/fr/basics/server-side-verification.mdx b/src/content/docs/fr/basics/server-side-verification.mdx index 71e30657132ad..dafd80a4e07d1 100644 --- a/src/content/docs/fr/basics/server-side-verification.mdx +++ b/src/content/docs/fr/basics/server-side-verification.mdx @@ -90,7 +90,8 @@ async function verifyToken(token) { headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ secret: 'your_secret_key', token }), }); - return response.json().verified || false; // Return verified field, default to false + const data = await response.json(); + return data.verified || false; // Return verified field, default to false } ``` @@ -187,7 +188,8 @@ npm install @prosopo/server Pour vérifier la réponse d'un utilisateur en utilisant JavaScript / TypeScript, importez simplement la fonction `verify` de `@prosopo/server` et passez-lui les données POST `procaptcha-response`. Les types peuvent être importés de `@prosopo/types`. ```typescript -import {ProsopoServer} from '@prosopo/server' +import {ProsopoServer, getServerConfig} from '@prosopo/server' +import {getPair} from '@prosopo/keyring' import {ApiParams} from '@prosopo/types' ... @@ -198,10 +200,13 @@ const payload = JSON.parse(event.body) const procaptchaResponse = payload[ApiParams.procaptchaResponse] // initialise the `ProsopoServer` class -const prosopoServer = new ProsopoServer(config) +const config = getServerConfig() +const pair = getPair(process.env.PROSOPO_SITE_PRIVATE_KEY, config.account.address) +const prosopoServer = new ProsopoServer(config, pair) // check if the captcha response is verified -if (await prosopoServer.isVerified(procaptchaResponse)) { +const result = await prosopoServer.isVerified(procaptchaResponse) +if (result.verified) { // perform CAPTCHA protected action } ``` diff --git a/src/content/docs/fr/welcome/index.mdx b/src/content/docs/fr/welcome/index.mdx index 75a51d164b62d..3874bea8157f4 100644 --- a/src/content/docs/fr/welcome/index.mdx +++ b/src/content/docs/fr/welcome/index.mdx @@ -26,7 +26,7 @@ Vous pouvez voir un exemple de bout en bout de la façon d'implémenter Procaptc Différents frameworks ont été intégrés avec Procaptcha. Vous pouvez trouver la documentation pour chaque framework ci-dessous : -- [Intégration React](/fr/framework-integrations/angular-integration/) +- [Intégration React](/fr/framework-integrations/react-integration/) - [Intégration Vue](/fr/framework-integrations/vue-integration/) - [Intégration Angular](/fr/framework-integrations/angular-integration/) - [Intégration Svelte](/fr/framework-integrations/svelte-integration/) diff --git a/src/content/docs/it/basics/client-side-rendering.mdx b/src/content/docs/it/basics/client-side-rendering.mdx index 682269b6c4f44..b484efd1c0d62 100644 --- a/src/content/docs/it/basics/client-side-rendering.mdx +++ b/src/content/docs/it/basics/client-side-rendering.mdx @@ -148,7 +148,7 @@ Può scegliere di implementare uno qualsiasi dei seguenti tipi di captcha quando Vari framework sono stati integrati con Procaptcha. Può trovare la documentazione per ciascun framework qui sotto: -- [Integrazione React](/it/framework-integrations/angular-integration/) +- [Integrazione React](/it/framework-integrations/react-integration/) - [Integrazione Vue](/it/framework-integrations/vue-integration/) - [Integrazione Angular](/it/framework-integrations/angular-integration/) - [Integrazione Svelte](/it/framework-integrations/svelte-integration/) diff --git a/src/content/docs/it/basics/invisible-captcha.mdx b/src/content/docs/it/basics/invisible-captcha.mdx index a2f333d83a460..0f57bdd2073b3 100644 --- a/src/content/docs/it/basics/invisible-captcha.mdx +++ b/src/content/docs/it/basics/invisible-captcha.mdx @@ -11,7 +11,7 @@ Il CAPTCHA invisibile è attualmente in **beta**. Funzionalità e comportamento ::: :::note[Restrizione Tier] -Il CAPTCHA invisibile è disponibile solo per gli utenti dei tier **Pro ed Enterprise**. Gli utenti del tier gratuito non possono accedere a questa funzionalità. +Il CAPTCHA invisibile è disponibile solo per gli utenti dei tier **Professional ed Enterprise**. Gli utenti del tier gratuito non possono accedere a questa funzionalità. ::: ## Panoramica @@ -219,18 +219,18 @@ const response = await fetch('https://api.prosopo.io/siteverify', { }, body: JSON.stringify({ secret: 'your_secret_key', - response: token, // Token from Procaptcha callback - remoteip: userIP // Optional + token: token, // Token from Procaptcha callback + ip: userIP // Optional }) }); const result = await response.json(); -if (result.success) { +if (result.verified) { // Procaptcha verified successfully console.log('Verification successful'); } else { // Verification failed - console.log('Verification failed:', result['error-codes']); + console.log('Verification failed:', result.status); } ``` diff --git a/src/content/docs/it/basics/server-side-verification.mdx b/src/content/docs/it/basics/server-side-verification.mdx index b68cc4011748e..5827f0f94a95c 100644 --- a/src/content/docs/it/basics/server-side-verification.mdx +++ b/src/content/docs/it/basics/server-side-verification.mdx @@ -90,7 +90,8 @@ async function verifyToken(token) { headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ secret: 'your_secret_key', token }), }); - return response.json().verified || false; // Return verified field, default to false + const data = await response.json(); + return data.verified || false; // Return verified field, default to false } ``` @@ -187,7 +188,8 @@ npm install @prosopo/server Per verificare la risposta di un utente utilizzando JavaScript / TypeScript, importi semplicemente la funzione `verify` da `@prosopo/server` e le passi i dati POST `procaptcha-response`. I tipi possono essere importati da `@prosopo/types`. ```typescript -import {ProsopoServer} from '@prosopo/server' +import {ProsopoServer, getServerConfig} from '@prosopo/server' +import {getPair} from '@prosopo/keyring' import {ApiParams} from '@prosopo/types' ... @@ -198,10 +200,13 @@ const payload = JSON.parse(event.body) const procaptchaResponse = payload[ApiParams.procaptchaResponse] // initialise the `ProsopoServer` class -const prosopoServer = new ProsopoServer(config) +const config = getServerConfig() +const pair = getPair(process.env.PROSOPO_SITE_PRIVATE_KEY, config.account.address) +const prosopoServer = new ProsopoServer(config, pair) // check if the captcha response is verified -if (await prosopoServer.isVerified(procaptchaResponse)) { +const result = await prosopoServer.isVerified(procaptchaResponse) +if (result.verified) { // perform CAPTCHA protected action } ``` diff --git a/src/content/docs/it/welcome/index.mdx b/src/content/docs/it/welcome/index.mdx index 26decc19802d2..9d0285e3733f3 100644 --- a/src/content/docs/it/welcome/index.mdx +++ b/src/content/docs/it/welcome/index.mdx @@ -26,7 +26,7 @@ Può visualizzare un esempio end-to-end di come implementare Procaptcha in una s Vari framework sono stati integrati con Procaptcha. Può trovare la documentazione per ciascun framework qui sotto: -- [Integrazione React](/it/framework-integrations/angular-integration/) +- [Integrazione React](/it/framework-integrations/react-integration/) - [Integrazione Vue](/it/framework-integrations/vue-integration/) - [Integrazione Angular](/it/framework-integrations/angular-integration/) - [Integrazione Svelte](/it/framework-integrations/svelte-integration/) diff --git a/src/content/docs/pt-br/basics/client-side-rendering.mdx b/src/content/docs/pt-br/basics/client-side-rendering.mdx index 65c8eb242195b..12eb0aa3e0a47 100644 --- a/src/content/docs/pt-br/basics/client-side-rendering.mdx +++ b/src/content/docs/pt-br/basics/client-side-rendering.mdx @@ -158,7 +158,7 @@ Você pode escolher implementar qualquer um dos seguintes tipos de captcha ao re Vários frameworks foram integrados com o Procaptcha. Você pode encontrar a documentação para cada framework abaixo: -- [Integração React](/pt-br/framework-integrations/angular-integration/) +- [Integração React](/pt-br/framework-integrations/react-integration/) - [Integração Vue](/pt-br/framework-integrations/vue-integration/) - [Integração Angular](/pt-br/framework-integrations/angular-integration/) - [Integração Svelte](/pt-br/framework-integrations/svelte-integration/) diff --git a/src/content/docs/pt-br/basics/invisible-captcha.mdx b/src/content/docs/pt-br/basics/invisible-captcha.mdx index ad8def88f296f..38641ff892e6a 100644 --- a/src/content/docs/pt-br/basics/invisible-captcha.mdx +++ b/src/content/docs/pt-br/basics/invisible-captcha.mdx @@ -11,7 +11,7 @@ O CAPTCHA Invisível está atualmente em **beta**. Recursos e comportamento pode ::: :::note[Restrição de Nível] -O CAPTCHA Invisível está disponível apenas para usuários dos níveis **Pro e Enterprise**. Usuários do nível gratuito não podem acessar este recurso. +O CAPTCHA Invisível está disponível apenas para usuários dos níveis **Professional e Enterprise**. Usuários do nível gratuito não podem acessar este recurso. ::: ## Visão Geral @@ -219,18 +219,18 @@ const response = await fetch('https://api.prosopo.io/siteverify', { }, body: JSON.stringify({ secret: 'your_secret_key', - response: token, // Token do callback Procaptcha - remoteip: userIP // Opcional + token: token, // Token do callback Procaptcha + ip: userIP // Opcional }) }); const result = await response.json(); -if (result.success) { +if (result.verified) { // Procaptcha verificado com sucesso console.log('Verificação bem-sucedida'); } else { // Falha na verificação - console.log('Falha na verificação:', result['error-codes']); + console.log('Falha na verificação:', result.status); } ``` diff --git a/src/content/docs/pt-br/basics/server-side-verification.mdx b/src/content/docs/pt-br/basics/server-side-verification.mdx index 5d79102f71117..08867baad2ea0 100644 --- a/src/content/docs/pt-br/basics/server-side-verification.mdx +++ b/src/content/docs/pt-br/basics/server-side-verification.mdx @@ -91,7 +91,8 @@ async function verifyToken(token) { headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ secret: 'your_secret_key', token }), }); - return response.json().verified || false; // Retornar campo verified, padrão false + const data = await response.json(); + return data.verified || false; // Retornar campo verified, padrão false } ``` @@ -189,7 +190,8 @@ Para verificar a resposta de um usuário usando JavaScript / TypeScript, simples os dados POST `procaptcha-response`. Os tipos podem ser importados de `@prosopo/types`. ```typescript -import {ProsopoServer} from '@prosopo/server' +import {ProsopoServer, getServerConfig} from '@prosopo/server' +import {getPair} from '@prosopo/keyring' import {ApiParams} from '@prosopo/types' ... @@ -200,10 +202,13 @@ const payload = JSON.parse(event.body) const procaptchaResponse = payload[ApiParams.procaptchaResponse] // inicializar a classe `ProsopoServer` -const prosopoServer = new ProsopoServer(config) +const config = getServerConfig() +const pair = getPair(process.env.PROSOPO_SITE_PRIVATE_KEY, config.account.address) +const prosopoServer = new ProsopoServer(config, pair) // verificar se a resposta do captcha está verificada -if (await prosopoServer.isVerified(procaptchaResponse)) { +const result = await prosopoServer.isVerified(procaptchaResponse) +if (result.verified) { // executar ação protegida por CAPTCHA } ``` diff --git a/src/content/docs/pt-br/welcome/index.mdx b/src/content/docs/pt-br/welcome/index.mdx index 38f44683055e0..a41ff298f6a4f 100644 --- a/src/content/docs/pt-br/welcome/index.mdx +++ b/src/content/docs/pt-br/welcome/index.mdx @@ -30,7 +30,7 @@ de como executar os exemplos estão na documentação nos links anteriores. Vários frameworks foram integrados com Procaptcha. Você pode encontrar a documentação para cada framework abaixo: -- [Integração com React](/pt-br/framework-integrations/angular-integration/) +- [Integração com React](/pt-br/framework-integrations/react-integration/) - [Integração com Vue](/pt-br/framework-integrations/vue-integration/) - [Integração com Angular](/pt-br/framework-integrations/angular-integration/) - [Integração com Svelte](/pt-br/framework-integrations/svelte-integration/) diff --git a/src/i18n/en/nav.ts b/src/i18n/en/nav.ts index 0e6aea8a13ebf..c2ec9ce1d2bfd 100644 --- a/src/i18n/en/nav.ts +++ b/src/i18n/en/nav.ts @@ -96,6 +96,22 @@ export default [ slug: 'advanced/audit', key: 'advanced/audit', }, + {text: 'Prosopo Protect (Edge)', header: true, type: 'learn', key: 'protect-edge'}, + { + text: 'Overview', + slug: 'protect-edge/', + key: 'protect-edge/', + }, + { + text: 'Cloudflare Worker', + slug: 'protect-edge/cloudflare-worker', + key: 'protect-edge/cloudflare-worker', + }, + { + text: 'AWS Lambda@Edge', + slug: 'protect-edge/lambda-edge', + key: 'protect-edge/lambda-edge', + }, {text: 'Framework integrations', header: true, type: 'learn', key: 'framework-integrations'}, { text: 'Angular Integration',