PluginProbe
SureCookie – GDPR Cookie Consent Banner, Cookie Scanner & Script Blocking / trunk
SureCookie – GDPR Cookie Consent Banner, Cookie Scanner & Script Blocking vtrunk
1.5.0 1.4.0 1.3.0 1.3.1 trunk 0.0.0-alpha.1 0.0.0-alpha.2 0.0.0-alpha.3 0.0.1-beta.1 0.0.1-beta.2 0.0.1-beta.3 0.0.1-beta.4 1.0.0 1.1.0 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4
surecookie / inc / modules / services / api.php

api.php in SureCookie – GDPR Cookie Consent Banner, Cookie Scanner & Script Blocking trunk, at inc/modules/services/api.php

191 lines 5.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Known Services API.
4 *
5 * Powers the Known Services library: a full catalog listing (every service,
6 * including cookieless ones, with tier + counts) plus the installed + detected
7 * state, and the atomic add/remove endpoints. Blocking is independent of this
8 * registry, so these endpoints only manage the declared/policy state.
9 *
10 * @package SureCookie\Inc\Modules\Services
11 * @since 1.3.0
12 */
13
14 namespace SureCookie\Inc\Modules\Services;
15
16 use SureCookie\Inc\API\Base;
17 use SureCookie\Inc\Functions\Cookie_Identity;
18 use SureCookie\Inc\Services\KnownServicesService;
19 use SureCookie\Inc\Traits\GetInstance;
20 use WP_REST_Response;
21 use WP_REST_Server;
22
23 if ( ! defined( 'ABSPATH' ) ) {
24 exit; // Exit if accessed directly.
25 }
26
27 /**
28 * Api - the Known Services REST controller (GET/POST/DELETE /known-services).
29 *
30 * @since 1.3.0
31 */
32 class Api extends Base {
33 use GetInstance;
34
35 /**
36 * Route path.
37 *
38 * @since 1.3.0
39 */
40 protected const ROUTE = '/known-services';
41
42 /**
43 * Register API routes.
44 *
45 * @since 1.3.0
46 * @return void
47 */
48 public function register_routes(): void {
49 register_rest_route(
50 $this->get_api_namespace(),
51 self::ROUTE,
52 [
53 'methods' => WP_REST_Server::READABLE,
54 'callback' => [ $this, 'get_known_services' ],
55 'permission_callback' => [ $this, 'validate_permission' ],
56 ]
57 );
58
59 register_rest_route(
60 $this->get_api_namespace(),
61 self::ROUTE . '/(?P<slug>[a-z0-9-]+)',
62 [
63 [
64 'methods' => WP_REST_Server::CREATABLE, // POST: install.
65 'callback' => [ $this, 'install_service' ],
66 'permission_callback' => [ $this, 'validate_permission' ],
67 ],
68 [
69 'methods' => WP_REST_Server::DELETABLE, // DELETE: uninstall.
70 'callback' => [ $this, 'uninstall_service' ],
71 'permission_callback' => [ $this, 'validate_permission' ],
72 ],
73 ]
74 );
75 }
76
77 /**
78 * Full catalog + installed + detected state for the library.
79 *
80 * @param \WP_REST_Request<array<string, mixed>> $request Request.
81 * @since 1.3.0
82 * @return WP_REST_Response { services:[], installed:[], detected:[] }.
83 */
84 public function get_known_services( $request ): WP_REST_Response {
85 $catalog = Services_Source::get_instance()->get_catalog();
86 $installed = Installed_Services::get_instance()->get_installed();
87 $services = [];
88
89 foreach ( $catalog as $slug => $service ) {
90 if ( ! is_string( $slug ) || ! is_array( $service ) ) {
91 continue;
92 }
93
94 // Patterns are matchers, not cookies: install() will not add them, so the
95 // library card must not count or list them either, or it promises seven
96 // cookies for Google Analytics and adds five.
97 $cookies = array_values(
98 array_filter(
99 (array) ( $service['cookies'] ?? [] ),
100 static fn( $cookie ): bool => is_array( $cookie )
101 && ! Cookie_Identity::is_pattern( (string) ( $cookie['name'] ?? '' ) )
102 )
103 );
104 $summary = Services_Source::pattern_summary( $service );
105
106 $services[] = array_merge(
107 [
108 'slug' => $slug,
109 'label' => (string) ( $service['label'] ?? $slug ),
110 'description' => (string) ( $service['description'] ?? '' ),
111 'category' => (string) ( $service['category'] ?? 'uncategorized' ),
112 'pro' => ! empty( $service['pro'] ),
113 'cookieCount' => count( $cookies ),
114 'cookies' => $cookies,
115 'resources' => Services_Source::pattern_lists( $service ),
116 ],
117 $summary
118 );
119 }
120
121 return new WP_REST_Response(
122 [
123 'services' => $services,
124 'installed' => array_values( $installed ),
125 'detected' => $this->detected_slugs( array_keys( $catalog ) ),
126 ],
127 200
128 );
129 }
130
131 /**
132 * Install a known service: declare its cookies + record the registry entry.
133 * Pro services require an active Pro license (enforced here, not just in UI).
134 *
135 * @param \WP_REST_Request<array<string, mixed>> $request Request (slug URL param).
136 * @since 1.3.0
137 * @return WP_REST_Response
138 */
139 public function install_service( $request ): WP_REST_Response {
140 $slug = (string) $request->get_param( 'slug' );
141
142 // Shared with the known-services ability so the Pro gate has one
143 // definition and cannot be bypassed through the other path.
144 $blocked = ( new KnownServicesService() )->check_installable( $slug );
145
146 if ( $blocked !== null ) {
147 return new WP_REST_Response(
148 [
149 'success' => false,
150 'code' => $blocked['code'],
151 'message' => $blocked['message'],
152 ],
153 $blocked['code'] === 'unknown_service' ? 404 : 403
154 );
155 }
156
157 $result = Installed_Services::get_instance()->install( $slug );
158
159 return new WP_REST_Response( $result, empty( $result['success'] ) ? 400 : 200 );
160 }
161
162 /**
163 * Uninstall a known service: remove its declared cookies + registry entry.
164 *
165 * @param \WP_REST_Request<array<string, mixed>> $request Request (slug URL param).
166 * @since 1.3.0
167 * @return WP_REST_Response
168 */
169 public function uninstall_service( $request ): WP_REST_Response {
170 $slug = (string) $request->get_param( 'slug' );
171 $result = Installed_Services::get_instance()->uninstall( $slug );
172
173 return new WP_REST_Response( $result, 200 );
174 }
175
176 /**
177 * Catalog slugs detected in the most recent scan's resources.
178 *
179 * @param array<int, string> $slugs Catalog slugs to test.
180 * @since 1.3.0
181 * @return array<int, string>
182 */
183 private function detected_slugs( array $slugs ): array {
184 $resources = (array) get_option( SURECOOKIE_SCANNED_RESOURCES_OPTION, [] );
185 $matcher = Service_Matcher::get_instance();
186 $urls = $matcher->collect_resource_urls( [ $resources ] );
187
188 return array_values( $matcher->match_services( $slugs, $urls ) );
189 }
190 }
191