=== AIS FormGuard ===
Contributors: aistreamjp
Tags: contact form 7, spam, anti-spam, honeypot, bot
Requires at least: 7.1
Tested up to: 7.1
Requires PHP: 8.1
Stable tag: 1.0.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Easy-setup spam protection for Contact Form 7. Blocks bots, auto-blocks attack sources, and tags sales emails instead of blocking them.

== Description ==

The administration screens are available in Japanese only. Paid cloud sales-email detection is intended for Japanese-language inquiries only; local protection works regardless of language.

AIS FormGuard protects your Contact Form 7 forms from bot spam, and is designed for site owners who do not have an engineer on staff. A three-step setup wizard checks your environment, lets you choose a protection level, and verifies that everything works. It starts in **monitor mode**, which only records what it would have blocked, so you can confirm that no real inquiry is affected before you switch to **defense mode**.

**What makes AIS FormGuard different**

* **It tags, it does not block, anything that could be a real inquiry.** Many spam plugins discard whatever they dislike. If you turn on the optional external service, messages that look like sales solicitations are delivered with a tag in the subject line (and, if you wish, to a different recipient), so a genuine inquiry that is misjudged is never lost. Only clear bot signals are blocked.
* **See before you block.** It starts in monitor mode, which records what it would have blocked without blocking anything. You switch to defense mode only after you have checked the results.
* **Several independent signals, on your own server, with nothing to register or buy.** Honeypot, signed token, minimum submission time, rate limit, link counter and duplicate detection all run locally and are free. Only the optional sales-email detection needs an API key from a paid plan. There is no CAPTCHA, the plugin adds no JavaScript or stylesheet to your pages, and it contacts an external server only when the site administrator enters an API key and turns on the optional integration.
* **Repeat offenders are blocked automatically.** Sources that keep triggering strong bot signals are blocked temporarily. While blocked, their submissions are treated as spam by Contact Form 7 and no email is sent. Similar events are grouped into one log line, and a safety check keeps the feature off when the site is behind a proxy it cannot identify.
* **Built for people without an engineer.** A three-step wizard, plain-language reasons for each detection, a weekly summary email, and a diagnostic summary that never contains message content.

**Protection that runs entirely on your own site**

* Hidden honeypot field.
* Signed timestamp token that detects forged forms and submissions made too quickly after the form was displayed.
* Per-IP rate limit.
* URL count and duplicate-message checks.
* Automatic temporary blocking of sources that keep triggering strong bot signals (see below).

**Automatic blocking of attack sources (defense mode only)**

When the same source repeatedly triggers a strong bot signal (a filled honeypot field or a missing token) within a short time, it is blocked for a limited time. While a source is blocked, its form submissions are treated as spam by Contact Form 7, so no email is sent, and the other checks are skipped. The dashboard lists blocked sources, lets you unblock them, and gives you a copy-and-paste list that you can add to your firewall or CDN.

To avoid blocking all visitors by mistake, automatic blocking is disabled when the site appears to be behind a proxy or CDN (such as Cloudflare) and you have not told the plugin which proxies to trust.

**Dashboard for non-engineers**

* Seven-day totals and a day-by-day graph.
* Reasons for each detection, shown in plain language.
* Similar events are grouped into one line with a counter, so a large attack does not flood your database.
* Weekly summary email.
* One-click return to monitor mode, and a diagnostic summary you can send to support (it contains no message content).

**Optional: sales-email detection with an external service**

With an API key from a paid plan, the plugin can ask the AIS FormGuard judgement service whether a message that passed the local checks looks like a sales solicitation. Messages judged to be sales solicitations are **not blocked**. They are delivered with a tag in the subject line (for example "【営業の可能性】"), optionally to a different recipient, so that a genuine inquiry that is misjudged is never lost. This feature is **off by default**. See "External services" below for exactly what is sent.

**Fail-open by design**

If anything goes wrong (for example, the optional service is unreachable or slow), the message is allowed through instead of being blocked.

**What it does not do**

* It is not a CAPTCHA. It can be used alongside Cloudflare Turnstile, Akismet or reCAPTCHA.
* By itself, the plugin does not read the wording of messages. Judging whether a message is a sales solicitation is done only by the optional external service.
* It works with Contact Form 7 only.

**Language**

The administration screens are currently available in Japanese only. Paid sales-email detection is intended for Japanese-language inquiries only.

== Installation ==

1. Install and activate Contact Form 7 (version 5.4 or later).
2. Upload the `ais-formguard` folder to the `/wp-content/plugins/` directory, or install the plugin through the WordPress plugins screen.
3. Activate the plugin through the "Plugins" screen. The setup wizard opens automatically.
4. Follow the three steps (environment check, protection level, verification). The plugin starts in monitor mode.
5. After a week or so, review the "Recent detections" list on the dashboard. If no genuine inquiry was flagged, switch to defense mode.

If your site is behind Cloudflare or another proxy/CDN, also read the FAQ entry about trusted proxies, and exclude the page that contains your form from page caching.

== Frequently Asked Questions ==

= Do I need Contact Form 7? =

Yes. AIS FormGuard works only with Contact Form 7 (5.4 or later).

= Does the plugin send any data to an external server by default? =

No. All of the protection described above runs on your own site. The plugin contacts an external server only when the site administrator enters an API key and turns on the optional integration.

= Can it block genuine visitors? =

It starts in monitor mode, which blocks nothing, so you can check first. In defense mode, a message is blocked only when it shows signs of automation, such as a filled hidden field, a forged token, a submission that is far too fast, repeated messages, or an unusual number of links. Messages that look like sales solicitations are never blocked; they are delivered with a tag in the subject line. If a visitor is blocked by mistake, you can unblock them from the dashboard, and you can add addresses that must never be blocked.

= How is this different from other spam plugins for Contact Form 7? =

Most plugins decide only between "accept" and "block". AIS FormGuard adds a third outcome: a message that might be a sales solicitation, but might also be a real inquiry, is delivered with a tag in the subject line instead of being discarded. It also offers a monitor mode that blocks nothing while you check the results, runs its checks on your own site without registering or buying anything (only the optional sales-email detection needs an API key from a paid plan), and temporarily blocks sources that keep sending obvious bot traffic. Other plugins may suit you better if you want to block sales messages outright or want a different approach; AIS FormGuard is designed to avoid losing a genuine inquiry.

= How does this compare with Cloudflare Turnstile? =

They are complementary. Turnstile (a feature of Contact Form 7) checks in the visitor's browser that the visitor is likely to be a real browser. AIS FormGuard looks at how a submission behaves and, optionally, at its content. Contact Form 7 runs its Turnstile check before AIS FormGuard does, so submissions rejected by Turnstile are not seen by this plugin.

= My site is behind Cloudflare or another proxy. What do I need to do? =

Enter the IP ranges of your proxy in "Trusted proxies" (Dashboard, "Automatic blocking of attack sources"). Until you do, the plugin cannot tell your visitors apart and, for safety, automatic blocking stays off. Also exclude the page that contains your form from page caching.

= Can it stop all sales emails? =

No. Automated sales mailers are fairly easy to recognize, but a sales message written by hand in natural language is hard to distinguish from a genuine inquiry. This is why such messages are tagged and delivered rather than blocked.

= What data does the plugin store? =

See the "Privacy" section below.

= What happens when I uninstall the plugin? =

The plugin's settings, scheduled tasks, and database tables are deleted.

== Screenshots ==

1. Setup wizard: environment check.
2. Dashboard: status, seven-day totals, daily graph, and recent detections.
3. Automatic blocking of attack sources: settings, blocked sources, and the copy-and-paste list.
4. Optional sales-email detection settings.

== Privacy ==

**Data stored on your site**

* A log table (`{prefix}aisfg_log`) that records the time, form ID, decision, reason codes, a hit counter, and the visitor's IP address with its last part masked (the last octet for IPv4, the lower 80 bits for IPv6). **The content of messages is never stored.** Log entries are deleted after 30 days by default.
* A table of blocked sources (`{prefix}aisfg_ban`) that records the full IP address of each blocked source, the reason, counters, and timestamps. Entries are deleted 7 days after the block expires, or when you unblock the source.
* Short-lived counters (WordPress transients) keyed by a hash of the IP address.
* Plugin settings. If you use the optional service, the API key you enter is stored in the WordPress options table.

IP addresses can be personal data under some privacy laws. We recommend mentioning the use of this plugin in your site's privacy policy.

**Data sent to external services**

Only if you enable the optional sales-email detection. See "External services".

== External services ==

This plugin can optionally connect to the **AIS FormGuard judgement service**, operated by AIStream Corporation (https://www.aistream.co.jp/), which judges whether a message looks like a sales solicitation. The address of the service is built into the plugin. **This feature is disabled by default.** The plugin contacts the service only after the site administrator enters an API key and turns on "営業メール判定を使う" (use sales-email detection) in the settings.

Developers can point the plugin to a different endpoint with the `AISFG_API_URL` constant in wp-config.php or the `aisfg_api_url` filter. Only https URLs without credentials, query or fragment are accepted. Data is then sent to that host instead.

**What is sent, and when**

* `POST /v1/evaluations` — When the optional integration is on, for each Contact Form 7 submission that passes the local checks (including in monitor mode; quota is consumed only when the AI model is used for the judgement): a random request ID, the site URL (`site_url` is always sent), the form ID, the visitor's IP address with its last part masked, and these signals: elapsed milliseconds, honeypot (always false at this stage, because a filled honeypot is blocked locally and never sent), URL count, content length, and local_reasons (an empty list, because only submissions that passed local checks are sent). The plugin also sends all submitted field values as one text payload (including names), with email addresses and phone numbers replaced by placeholders and truncated to 2,000 characters. The text may still contain other personal information entered by the visitor. The message text is processed in memory by our judgement system and is not stored or written to server logs. The server keeps only: (1) a keyed hash (HMAC-SHA-256) of the normalized text together with the decision, so that identical messages are not re-judged; it expires after 24 hours and is then deleted automatically; and (2) an evaluation record with the site ID, request ID, form ID, masked IP address, message length, decision, score, reason codes, whether the AI model was used, processing time, timestamps and a repeat counter; it expires after 30 days and is then deleted automatically. Neither contains the message text.
* `POST /v1/sites/activations` — Only when the administrator turns the integration on, saves settings, and the API key is not yet bound to this site (after confirming the domain-bind checkbox): the site URL, the plugin version, and the WordPress version. If the key is already bound to this site, this request is not sent.
* `GET /v1/licenses/current` — When the integration is on: when the administrator saves settings, clicks "契約情報を更新", or opens the settings screen, and also during a Contact Form 7 submission if the cached license information has expired (responses are cached for up to one hour, so this happens at most once per hour): the site URL is sent as a query parameter.
* Purchase page — When the administrator clicks the purchase link, the browser opens a page operated by AIStream Corporation. The plugin itself does not contact that page. The fragment after `#` contains a lookup value derived from the API key (not the key itself) and this site's domain. The page sends those values to the AIS FormGuard API. Payment is made with Stripe Checkout (`checkout.stripe.com`). Stripe's terms: https://stripe.com/legal/ssa — Stripe's privacy policy: https://stripe.com/privacy
* The API key is sent in an HTTP header with every request to the management server.

When the quota is used up, the server keeps judging with its dictionary rules only and no quota is consumed. When the license expires or the site is suspended, or the API key is no longer valid, the plugin turns the integration off automatically and works exactly like the free version (local checks only).

**What is not sent**

WordPress user accounts and passwords, and any data from sites where the optional integration is not enabled. When the integration is on, email addresses and phone numbers in the message text are replaced with placeholders before transmission; other field values (including names) are sent.

**Service terms and privacy policy**

* Terms of use: https://www.aistream.co.jp/ais-form-guard-tou/
* Privacy policy: https://www.aistream.co.jp/privacy-policy/

**Other services**

This plugin does not contact Cloudflare. Cloudflare Turnstile, if you use it, is a feature of Contact Form 7 and is configured there. Purchases use Stripe Checkout as described above.

== Changelog ==

= 1.0.0 =
* Initial public release.
* Local protection for Contact Form 7: honeypot, signed timestamp token, minimum submission time, per-IP rate limit, URL count and duplicate-message checks.
* Setup wizard, monitor and defense modes, dashboard, and weekly summary email.
* Automatic temporary blocking of sources that repeatedly trigger strong bot signals (defense mode only), with a safety check for untrusted proxies or CDNs.
* Optional sales-email detection with an external service (off by default). Messages judged to be sales solicitations are tagged, not blocked.

== Upgrade Notice ==

= 1.0.0 =
Initial public release. Optional sales-email detection sends masked enquiry text when enabled. Default service wait is 10s (max 15). Early renewal carries remaining quota into the next period. Free mode (detection off) does not contact the management server.
