Skip to content

feat(content-gate): expose institutional IP allowlist endpoint#4685

Open
rbcorrales wants to merge 3 commits intotrunkfrom
feat/content-gate-ip-allowlist
Open

feat(content-gate): expose institutional IP allowlist endpoint#4685
rbcorrales wants to merge 3 commits intotrunkfrom
feat/content-gate-ip-allowlist

Conversation

@rbcorrales
Copy link
Copy Markdown
Member

All Submissions:

Changes proposed in this Pull Request:

Adds a GET /newspack/v1/institutional-access/ip-allowlist REST endpoint, gated by manage_options, that returns the institutional IP allowlist configured for the site. Designed for external systems to mirror the list locally and decide gating without hitting the origin per request.

The endpoint exposes only IP rules. Email domain and reader data rules are not surfaced. Entries that fail IPv4 or CIDR validation are dropped before being returned. A newspack_content_gate_ip_allowlist filter is provided so other plugins can augment the list.

This PR also includes a security fix for a bug in IP_Access_Rule::ip_matches_ranges() (introduced in #4574): the (int) $bits cast silently coerced any value that wasn't numeric to 0, causing typo'd entries like 10.0.0.5/foo or 10.0.0.5/ to match every IP. Validation is now tightened with ctype_digit() before the cast. Caused by admin input only, not externally exploitable, but operationally risky.

Closes NPPM-2770.

How to test the changes in this Pull Request:

  1. Configure an institution with a valid IP range (e.g. 192.168.1.0/24,10.0.0.5) under Audience > Access Control > Institutions.
  2. As an administrator, curl -u admin:app_password https://your-site.com/wp-json/newspack/v1/institutional-access/ip-allowlist. Confirm the response is a JSON array of { id, name, ip_ranges } entries, sorted by id ascending.
  3. Hit the endpoint as an unauthenticated user. Confirm a 401 response.
  4. Hit the endpoint as a user without admin permissions (e.g. subscriber). Confirm a 403 response.
  5. Configure a second institution with no IP range. Confirm it does NOT appear in the response.
  6. Configure an institution with a mix of valid and malformed entries (e.g. 10.0.0.1,not-an-ip,10.0.0.5/foo,192.168.1.0/24,10.0.0.5/40). Confirm only the valid ones (10.0.0.1, 192.168.1.0/24) appear.
  7. Confirm the existing /check endpoint (POST and GET) still works unchanged.
  8. Verify the security fix: configure an institution with 10.0.0.0/foo as its IP range. An unrelated visitor IP like 203.0.113.5 must NOT pass the institutional IP gate. Previously it would have, due to the loose validation.

Other information:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your changes, as applicable?
  • Have you successfully ran tests with your changes locally?

rbcorrales and others added 2 commits April 28, 2026 17:00
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an admin-gated REST API endpoint to expose the institutional IPv4/CIDR allowlist so external systems can mirror it, and tightens CIDR parsing to prevent malformed prefixes from matching all IPs.

Changes:

  • Added GET /newspack/v1/institutional-access/ip-allowlist (gated by manage_options) returning { id, name, ip_ranges } entries and applying newspack_content_gate_ip_allowlist filter.
  • Centralized IPv4/CIDR parsing via parse_ip_ranges() and reused it for both allowlist output and matching.
  • Hardened CIDR validation to prevent non-numeric prefixes (e.g. /foo, /) from being treated as /0.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
includes/content-gate/class-ip-access-rule.php Registers new allowlist route, implements allowlist callback + schema, and introduces stricter IP/CIDR parsing used by matching.
tests/unit-tests/content-gate/class-ip-access-rule.php Adds unit tests for malformed CIDR behavior and comprehensive endpoint behavior/shape tests for the new allowlist route.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread includes/content-gate/class-ip-access-rule.php
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rbcorrales rbcorrales marked this pull request as ready for review April 28, 2026 22:17
@rbcorrales rbcorrales requested a review from a team as a code owner April 28, 2026 22:17
@rbcorrales rbcorrales added the [Status] Needs Review The issue or pull request needs to be reviewed label Apr 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Status] Needs Review The issue or pull request needs to be reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants