=== InlineShield Signup Protection ===
Contributors: inlineshield
Tags: registration, fraud, spam, woocommerce, signup
Requires at least: 6.0
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 1.0.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Screens WordPress and WooCommerce sign-ups with InlineShield and stops fake, disposable and multi-account registrations before the account exists.

== Description ==

InlineShield checks every new sign-up for disposable and throw-away email addresses, plus-address and dot aliases of an existing inbox, bots and automation, VPN, proxy and data-centre traffic, and other signs of bonus abuse and multi-accounting. It answers in a fraction of a second with a verdict:

* **ALLOWED**: the account is created.
* **QUARANTINED** ("review"): you choose: let them sign up and flag the account, let them sign up but block login until you approve them in the InlineShield Review queue, or refuse the sign-up.
* **BLOCKED**: the sign-up is refused with a neutral message ("We couldn't create your account. Please contact support.").

What the plugin does:

* Protects the WordPress registration form (wp-login.php?action=register), WooCommerce My Account registration and, optionally, account creation at WooCommerce checkout. Accounts created at checkout are screened only when the "WooCommerce checkout" protection is on (it is off by default); My Account protection does not cover them.
* Adds the InlineShield browser check to those forms only, and verifies its token on the server (/siteverify). Without a token it screens on the server (/verify) with the email, IP address, browser user agent and username.
* Stores the result on the new user (request id, verdict, risk score, recommended action and status) and shows it in an "InlineShield" column on the Users screen.
* "Report fraud" and "Report legitimate" row and bulk actions on the Users screen send the real outcome back to InlineShield, which improves screening for your site.
* A signed webhook receiver (`/wp-json/inlineshield/v1/webhook`) applies your review decisions: signup.approved unblocks a held account, signup.rejected keeps it blocked.
* If InlineShield cannot be reached within 4 seconds, sign-ups are allowed (default) or refused, as you choose.
* Uses the WordPress HTTP API, so it works without the PHP curl extension.

= For developers =

* Filter `inlineshield_decision( $decision, $email )`: change the decision before it is applied. Set `$decision['outcome']` to `allow` or `refuse`.
* Action `inlineshield_screened( $user_id, $decision )`: runs after a screened account is created. `$decision['action']` is InlineShield's recommended action, for example for bonus systems: `allow`, `allow_no_bonus` (create the account but do not pay a sign-up bonus) or `review`. The signup.approved webhook can later set it to `require_kyc` (ask for identity verification before paying out).
* Action `inlineshield_review_decided( $user_id, $status, $data )`: runs when a review decision arrives by webhook.
* Filter `inlineshield_client_ip( $ip, $server )`: the plugin sends REMOTE_ADDR only and never trusts X-Forwarded-For. Behind a proxy or CDN you trust, return the visitor's address here.
* User meta: `_inlineshield_request_id`, `_inlineshield_verdict`, `_inlineshield_risk`, `_inlineshield_action`, `_inlineshield_status` (allowed, held, approved, rejected).

== External services ==

This plugin connects to InlineShield (https://inlineshield.io), a sign-up fraud screening service operated by InlineShield. It is required for the plugin to work.

* **When a visitor submits a protected registration form** (WordPress registration, WooCommerce My Account registration and, if enabled, WooCommerce checkout with account creation), the visitor's browser loads https://api.inlineshield.io/inlineshield.js and sends InlineShield the email address, the username, the time spent on the page and basic browser signals (time zone, languages, automation indicators), together with your public site key. InlineShield also sees the visitor's IP address and user agent.
* **Then your server** sends InlineShield the email address with the browser's token, or, when there is no token, the email address, IP address, user agent and username, authenticated with your API key.
* **When an administrator uses "Report fraud" or "Report legitimate"**, your server sends the stored request id and the outcome.
* **"Test connection"** on the settings page calls InlineShield's public health endpoint; nothing personal is sent.
* **InlineShield sends your site** signed webhooks with review decisions (request id, review id and decision; never an email address).

InlineShield terms of service: https://inlineshield.io/terms
InlineShield privacy policy: https://inlineshield.io/privacy

== Installation ==

1. Upload the plugin folder to `/wp-content/plugins/`, or install the ZIP from Plugins › Add New › Upload Plugin.
2. Activate "InlineShield Signup Protection".
3. In your InlineShield console (Setup), create an API key and a site key, and add your site's domain to the site key.
4. Open Settings › InlineShield, paste both keys and save.
5. Optional: to block login until approval, copy the webhook URL shown on the settings page into your InlineShield console's webhook settings and paste the webhook signing secret here.
6. Click "Test connection".

== Frequently Asked Questions ==

= Does it slow down registration? =

The check usually takes well under a second. The plugin waits at most 4 seconds in total for one sign-up (including a fallback from /siteverify to /verify); then your "unreachable" setting applies.

= What happens if InlineShield is down? =

By default sign-ups are allowed (fail open), stored with the verdict UNAVAILABLE. You can choose to refuse them instead.

= What does the visitor see when a sign-up is refused? =

It depends on where the refusal happens:

* When the browser check (inlineshield.js) already gets a BLOCKED answer, the form is not submitted and the script shows InlineShield's first reason under the email field, for example that disposable addresses are not accepted. Learned signals are only ever shown as one generic line.
* When the server refuses the sign-up (no browser check, a QUARANTINED answer in "Refuse the sign-up" mode, or the unreachable setting set to refuse), WordPress shows a neutral message: "We couldn't create your account. Please contact support." It does not say why.

= Can an attacker turn screening off by flooding the form? =

A flood can exhaust your InlineShield rate limit (HTTP 429) or monthly quota (HTTP 402). The plugin retries a rate-limited check once within its 4-second budget and logs every such answer; after that, your "If InlineShield is unreachable" setting applies. With the default "Allow the sign-up", sign-ups during that time are created with the verdict UNAVAILABLE (visible in the Users column). If that risk matters more to you than turning real people away during an outage, choose "Refuse the sign-up", and keep enough monthly quota.

= Are administrators ever blocked? =

No. The login block applies only to held or rejected accounts that are not administrators.

= What exactly does "block login until approved" block? =

Password logins (wp-login.php, the WooCommerce login form, XML-RPC), existing sessions (a held or rejected user is treated as logged out, including a customer the block checkout logged in right after the order) and application passwords. When InlineShield sends signup.rejected, all of the account's sessions are ended.

= Does it work with the WooCommerce block checkout? =

Yes, when the "WooCommerce checkout" protection is on (off by default; without it, accounts created at checkout are not screened, even with My Account protection on): every account a checkout creates is screened, with the classic checkout (also when the store requires an account and shows no "Create an account" box) and with the block checkout. The block checkout is screened on the server only (without the browser check). My Account registration works with any theme.

= Does it work on multisite? =

It is a single-site plugin. It cannot be network activated; activate it on each site that needs it. Sign-ups through the network's wp-signup.php are not screened.

= Does loading inlineshield.js on the checkout page affect PCI DSS? =

If you protect checkout account creation, inlineshield.js is loaded on the checkout page. PCI DSS 4.0 requirement 6.4.3 asks you to inventory and authorize every script on payment pages, so add it to your list (source https://api.inlineshield.io/inlineshield.js). The script never reads payment fields. Leave checkout protection off if you do not want any third-party script there.

= What does a privacy erasure request remove? =

The stored request id, verdict, risk score, recommended action, review id and reported outcome. The review status is kept (and reported as retained), because it is what keeps a held or rejected account blocked; it is removed when the account is deleted or the plugin is uninstalled.

= Does it need the curl extension? =

No. It uses the WordPress HTTP API.

== Screenshots ==

1. Settings › InlineShield: keys, the "review" and "unreachable" choices, protected forms and Test connection.
2. The Users screen with the InlineShield column (verdict, risk, recommended action, status) and the Report fraud / Report legitimate actions.
3. A refused sign-up on the WordPress registration form.

== Changelog ==

= 1.0.0 =
* First release: WordPress and WooCommerce sign-up screening, review modes, fail mode, Users column with feedback actions, signed webhook receiver, privacy exporter and eraser.

== Upgrade Notice ==

= 1.0.0 =
First release.
