StrikeScopeWP
WordPress contractor CRM: branded lead forms, Help Desk, and email automation.
by uncooluser · github.com/gatogodmode/strikescope-wp · website
Install
The author publishes release zips, so WP-CLI can install straight from GitHub:
wp plugin install https://github.com/gatogodmode/strikescope-wp/releases/download/v1.0.0/strikescope-wp-1.0.0.zipReadme
StrikeScopeWP
WordPress plugin for contractor sites: multi-step lead forms, lightweight CRM, Help Desk, branded emails, scheduling hooks, and optional REST/webhooks.
At a glance
| Area | What you get |
|---|---|
| Public form | React multi-step quote flow + optional Help Desk tab via [strikescope_form] |
| CRM | Lead custom post type, statuses, map dashboard, CSV export, sales-agent assignment |
| Help Desk | Ticket CPT, threaded email, status templates, inbound email webhook |
| Branding | Logo, form colors, phone, contact slug, footer — one source of truth for UI + emails |
| Comms | Per-service notification routing, customer follow-up, merge tags |
| Integrations | Turnstile, Google/Outlook calendar OAuth, scoped API keys, signed outbound webhooks (all optional) |
Data stays in your WordPress database unless you configure third-party services. The plugin does not phone home to the author or send telemetry.
Architecture
flowchart TB
subgraph Public["Public site"]
Shortcode["[strikescope_form]"]
React["React bundle<br/>assets/js + assets/css"]
Shortcode --> React
end
subgraph WP["WordPress (your server)"]
REST["REST API<br/>strikescope/v1/*"]
CPT["CPTs: leads, help tickets"]
Opts["wp_options<br/>settings + branding"]
Mail["wp_mail()"]
React -->|POST JSON| REST
REST --> CPT
REST --> Opts
REST --> Mail
end
subgraph Admin["wp-admin"]
Settings["StrikeScopeWP menus"]
CRM["Lead / ticket UI"]
Settings --> CPT
CRM --> CPT
end
subgraph Optional["Optional (you configure)"]
Turnstile["Cloudflare Turnstile"]
Cal["Google / Outlook calendar"]
Hook["Your webhook endpoints"]
Inbound["Email provider inbound"]
REST -.-> Turnstile
REST -.-> Hook
Inbound -.-> REST
Admin -.-> Cal
end
Public submission path
Both lead and help-ticket submissions use the same layered checks before anything is stored.
sequenceDiagram
participant Browser
participant WP as WordPress REST
participant Store as DB / wp_mail
Browser->>WP: POST /lead-form/submit or /help-ticket/submit
WP->>WP: wp_verify_nonce (wp_rest)
WP->>WP: Honeypot empty + min 3s elapsed
WP->>WP: IP rate limit (transient, SHA-256 IP hash)
WP->>WP: Turnstile verify (if secret configured)
WP->>WP: Allowlist validation + header-injection block
WP->>WP: Blacklist silent reject (email / ZIP / city / state)
alt Pass
WP->>Store: Save CPT + send emails
WP-->>Browser: success JSON
else Fail
WP-->>Browser: 4xx (generic message)
end
Admin vs integration access
flowchart LR
subgraph PublicREST["Public REST"]
Submit["/lead-form/submit<br/>/help-ticket/submit"]
end
subgraph AuthREST["Authenticated REST"]
Admin["manage_options<br/>asset build, email tests"]
LeadsAPI["API key or logged-in lead manager<br/>leads:read / write / export"]
Inbound["X-StrikeScope-Inbound-Secret<br/>/help-ticket/inbound"]
end
Submit -->|nonce + bot controls| OK1[Store submission]
Admin -->|WP capability| OK2[Admin actions]
LeadsAPI -->|HMAC-stored key + scope| OK3[Lead CRUD / export]
Inbound -->|hash_equals secret| OK4[Append ticket reply]
Features
Lead form & CRM
- Multi-step React form — service type, property, timeline, budget, contact/address; US-wide (no third-party parcel lookup).
- Shortcode mount —
[strikescope_form]on any page; auto-mount when the page slug matches Branding → contact page slug. - Lead CPT — each submission becomes a lead record with meta (services, contact, geo hash, assignment, status).
- Admin list & detail — filters, status workflow, internal notes, map view for geocoded leads.
- CSV export — admin or scoped API (
leads:export). - Sales agents — dedicated
strikescope_sales_agentrole; agents see only leads assigned to them (admins see all). - Blacklist — admin-defined email, ZIP, city, and state lists; matches fail with a generic validation error (no leak to submitter).
Help Desk
- Second tab on the same form — ticket category, priority, description (when enabled in settings).
- Ticket numbering & statuses — admin workflow with email notifications per status.
- Threaded email — reply tokens tie customer email threads back to tickets.
- Inbound webhook —
POST /strikescope/v1/help-ticket/inboundfor Postmark-style providers; requiresX-StrikeScope-Inbound-Secret(constant-time compare).
Branding & emails
- StrikeScopeWP → Branding — company name, logo URL, primary/accent/background colors, phone display, contact page slug, footer text.
- Form theming — colors flow to the React bundle via localized CSS variables (no hard-coded client palette in shipped assets).
- Merge tags —
%%COMPANY_NAME%%,%%PHONE%%,%%LOGO_URL%%, lead/ticket fields, etc., in HTML templates undertemplates/emails/. - Per-service routing — route notification emails by service type; customer follow-up template after lead submit.
Scheduler & integrations
- Calendar OAuth — optional Google / Microsoft Outlook connection for availability-style workflows (admin-only REST).
- REST API keys — prefixed keys (
spk_…); only HMAC-SHA256 hashes (keyed withwp_salt('auth')) stored in the database; scopes:leads:read,leads:write,leads:export. - Outbound webhooks — JSON POST on events (
lead.created,lead.assigned, etc.); optionalX-StrikeScope-Signature: sha256=<hmac>when a webhook secret is set. - Cloudflare Turnstile — optional; when a secret key is set, submissions without a valid token are rejected server-side.
Privacy & compliance hooks
- WordPress personal data exporters for leads and help tickets (by email).
- WordPress personal data eraser for leads.
- Raw client IP is not stored in lead meta; a SHA-256 hash of
REMOTE_ADDRis kept for abuse forensics.
Security (CyberSecurity specialist view)
This section describes trust boundaries, controls, and residual risk so security reviewers can assess deployment without reading every PHP file.
Threat model (summary)
| Asset | Primary threats | Plugin response |
|---|---|---|
| Lead/ticket PII in DB | Unauthorized read/write | WP capabilities, sales-agent scoping, API key scopes |
| Public form endpoints | Spam, credential stuffing, injection | Nonce, honeypot, timing, rate limit, Turnstile, validation |
| Admin / REST API | Key theft, privilege escalation | Hashed API keys, scope checks, manage_options for sensitive routes |
| Email / webhooks | Header injection, forged inbound | CRLF checks on fields; inbound shared secret + hash_equals |
| Distribution artifact | Secrets or client data in zip | CI forbidden-pattern scan on push/PR and release |
Out of scope for the plugin: hardening your host OS, WAF, TLS termination, database encryption at rest, SMTP auth, or WordPress core/plugin CVEs — those remain site-operator responsibilities.
Public attack surface
| Endpoint | Auth | Notes |
|---|---|---|
POST …/lead-form/submit |
WordPress REST nonce | Intentionally public; protected by bot/abuse layers |
POST …/help-ticket/submit |
Same | Disabled entirely when Help Desk is off (503) |
GET …/lead-form/assets |
— | Not a public write path; admin-only |
Controls on public POST handlers
wp_verify_nonce(…, 'wp_rest')— CSRF token tied to the localized script config.- Honeypot field (
website) — bots that fill hidden fields get a generic 400. - Minimum submit time (~3 seconds) — reduces drive-by automated posts.
- Rate limiting — per-IP counter in transients (
rate_limit_per_hoursetting); IP hashed with SHA-256 before use as transient key. - Cloudflare Turnstile — server-side
siteverifywhen secret key is configured; skipped only when secret is empty (dev-friendly, not production-recommended). - Strict allowlists — service types, property types, timelines, budgets must match plugin enums (
sanitize_key+in_array). - Length limits & sanitization —
sanitize_text_field, email validation, max field lengths. - Header injection guard — rejects values containing
\ror\n(email header smuggling). - Blacklist — silent reject for blocked email/ZIP/city/state (reduces attacker feedback).
Residual public risks
- Rate limits are per WordPress instance (transients), not global; high-volume attacks may need a WAF or edge rate limit.
- Client IP uses
REMOTE_ADDRonly — if you terminate TLS at a proxy, configure the server so WordPress sees the real client IP (or rate limits may target the proxy). - Turnstile off + weak
rate_limit_per_hour= higher spam volume (operational, not a bypass of auth).
Authentication & authorization
| Mechanism | Implementation |
|---|---|
| wp-admin settings | manage_options (and lead caps for CRM screens) |
| Sales agent isolation | Custom caps + post meta _lead_sales_agent; list queries filtered for agents |
| REST API keys | Plain key shown once at creation; stored hash compared with hash_equals |
| API scopes | leads:read, leads:write, leads:export — enforced per route |
| Session fallback | Logged-in users with lead-manager capability bypass API key for same routes |
| Help Desk inbound | X-StrikeScope-Inbound-Secret compared with hash_equals to configured secret |
| Outbound webhooks | Optional HMAC-SHA256 body signature header for receiver verification |
API keys are generated with random_bytes; prefix spk_ aids log scanning without exposing full secrets.
Data protection & third parties
flowchart LR
subgraph Local["Default: stays on your WP DB"]
Leads[(Lead CPT)]
Tickets[(Ticket CPT)]
Settings[(Options)]
end
subgraph Egress["Optional egress — you enable"]
CF["Cloudflare Turnstile<br/>token + IP"]
Geo["Nominatim / maps links<br/>address geocoding"]
Cal2["Google / Microsoft<br/>OAuth tokens"]
WH["Your webhook URLs<br/>lead JSON"]
SMTP["Your SMTP / wp_mail<br/>notification content"]
end
Leads --> SMTP
Leads -.-> WH
Form -.-> CF
Leads -.-> Geo
Admin -.-> Cal2
- No vendor telemetry to StrikeScopeWP author servers.
- Secrets (Turnstile secret, OAuth client secrets, webhook HMAC secrets, inbound secret) live in
wp_options— protect backups and DB access like any credential store. - Distribution CI (
.github/workflows/distribution-check.yml) blocks commits containing forbidden client-brand strings and common credential patterns; release workflow runs the same check before zipping.
Security hardening checklist (operators)
- Production forms — enable Turnstile; set a sensible
rate_limit_per_hour; keep WordPress core and plugins patched. - HTTPS everywhere — REST nonces and cookies require TLS on the public site.
- API keys — issue least-privilege scopes; revoke unused keys; never commit plain keys to git.
- Webhooks — use HTTPS endpoints only; configure shared secret and verify
X-StrikeScope-Signatureon your receiver. - Help Desk inbound — rotate
inbound_secretif leaked; restrict inbound route to provider IP ranges at the firewall when possible. - Sales agents — use the dedicated role instead of sharing administrator accounts.
- Backups — encrypt backups containing
wp_optionsand lead/ticket tables. - File integrity — install only from GitHub Releases or your own
release.sh/release.ps1build after CI passes.
What this plugin does not provide
- SIEM, IDS, or centralized logging (use server/WP audit plugins).
- Field-level encryption at rest for PII.
- GDPR “data processing agreement” with third parties — you control which optional integrations are enabled.
- Guaranteed spam elimination — layered controls reduce abuse; human review may still be needed.
Quick start
-
Install from Releases (
strikescope-wp-x.x.x.zip) or clone this repo and runrelease.ps1/release.shafter building assets. -
Plugins → Add New → Upload Plugin → activate StrikeScopeWP.
-
Create a contact page with the shortcode:
[strikescope_form] -
StrikeScopeWP → Branding — company name, logo, colors, phone, contact page slug, footer text.
-
StrikeScopeWP → Contact Form — notification emails, Turnstile, services, Help Desk (Form tab shows branding-derived phone/slug as read-only with link to Branding).
Configuration
| What | Where |
|---|---|
| Logo, colors, phone, contact slug, footer | StrikeScopeWP → Branding |
| Notification emails, Turnstile, services, Help Desk | StrikeScopeWP → Contact Form |
| API keys, webhooks, calendar OAuth | StrikeScopeWP → Integrations / API / Webhooks |
Phone and contact page slug have a single source of truth in Branding (form, emails, scheduler links, auto-mount).
Build from source
Requires Node 20+ and npm.
# Build React bundle into assets/
./build-assets.sh # Linux/macOS
./build-assets.ps1 # Windows PowerShell
# WordPress-ready zip (runtime files only — no frontend/ or node_modules/)
./release.sh
./release.ps1Read the full README on GitHub →
Releases
| Tag | Published | Asset | Downloads |
|---|---|---|---|
| v1.0.0 | Jun 21, 2026 | strikescope-wp-1.0.0.zip | 0 |