1+ <?php
2+
3+ /**
4+ * Caching
5+ *
6+ * Rocket-related Caching, see unmus_rocket.php
7+ * Following is referring to WP REST API (Plugin WP-REST-CACHE)
8+ *
9+ * @package unmus
10+ * @since 0.9
11+ *
12+ * @link https://epiph.yt/en/blog/2025/activitypub-plugin-and-accidental-ddos/
13+ */
14+
15+ // Security: Stops code execution if WordPress is not loaded
16+ if (!defined ('ABSPATH ' )) { exit ; }
17+
18+ // Import Caching Class from WP_Rest_Cache_Plugin
19+ use WP_Rest_Cache_Plugin \Includes \Caching \Caching ;
20+
21+ /**
22+ * Get ActivityPub REST API Namespace
23+ *
24+ * @since 0.9
25+ *
26+ * @return string The ActivityPub REST API namespace
27+ */
28+
29+ function unmus_cache_get_activitypub_restapi_namespace () {
30+
31+ $ activitypub_api_namespace = 'activitypub/1.0 ' ;
32+ return $ activitypub_api_namespace ;
33+ }
34+
35+ /**
36+ * Get ActivityPub endpoints to be cached
37+ *
38+ * @since 0.9
39+ *
40+ * @return array The ActivityPub endpoints to be cached
41+ */
42+
43+ function unmus_cache_get_activitypub_endpoints () {
44+
45+ $ endpoints = [ unmus_cache_get_activitypub_restapi_namespace () => [
46+ '' ,
47+ 'actors ' ,
48+ 'application ' ,
49+ 'collections ' ,
50+ 'comments ' ,
51+ 'inbox ' ,
52+ 'interactions ' ,
53+ 'nodeinfo ' ,
54+ 'posts ' ,
55+ 'users ' ,
56+ 'webfinger '
57+ ]];
58+
59+ return $ endpoints ;
60+ }
61+
62+ /**
63+ * Add ActivityPub Endpoints to Cache
64+ *
65+ * @since 0.9
66+ *
67+ * @param array Endpoints that are allowed to be cached
68+ * @return array Allowed Endpoints extended with ActivityPub
69+ */
70+
71+ function unmus_cache_add_activitypub_endpoints ( $ allowed_endpoints ) {
72+
73+ $ activitypub_api_namespace = unmus_cache_get_activitypub_restapi_namespace ();
74+ $ endpoints = unmus_cache_get_activitypub_endpoints ();
75+
76+ if (!isset ($ allowed_endpoints [$ activitypub_api_namespace ])) {
77+ $ allowed_endpoints [$ activitypub_api_namespace ] = $ endpoints [$ activitypub_api_namespace ];
78+ }
79+
80+ return $ allowed_endpoints ;
81+
82+ }
83+ add_filter ( 'wp_rest_cache/allowed_endpoints ' , 'unmus_cache_add_activitypub_endpoints ' , 10 , 1 );
84+
85+ /**
86+ * Is ActivityPub Endpoint
87+ *
88+ * @param string $uri URI to test
89+ * @return bool Whether the current endpoint is an ActivityPub endpoint
90+ */
91+
92+ function unmus_is_activitypub_endpoint ( string $ uri ) :bool {
93+
94+ $ search = '/ ' . unmus_cache_get_activitypub_restapi_namespace () . '/ ' ;
95+
96+ return \str_contains ( $ uri , $ search ) || \str_contains ( $ uri , 'rest_route= ' . \rawurlencode ( $ search ) );
97+ }
98+
99+ /**
100+ * Determine Object Type
101+ *
102+ * @since 0.9
103+ *
104+ * @param string $object_type Object type
105+ * @param string $cache_key Object key
106+ * @param mixed $data Data to cache
107+ * @param string $uri Request URI
108+ * @return string Updated object type
109+ */
110+
111+ function unmus_cache_determine_object_type ( $ object_type , $ cache_key , $ data , $ uri ) {
112+
113+ if (unmus_is_activitypub_endpoint ( $ uri ) ) {
114+ $ object_type = 'ActivityPub ' ;
115+ return $ object_type ;
116+ }
117+ }
118+ add_filter ( 'wp_rest_cache/determine_object_type ' , 'unmus_cache_determine_object_type ' , 10 , 4 );
119+
120+ /**
121+ * Reset Cache by Transition Post Status
122+ *
123+ * @since 0.9
124+ *
125+ * @param string $new_status New post status
126+ * @param string $old_status Old post status
127+ * @param \WP_Post $post Post object
128+ */
129+
130+ function unmus_cache_reset_by_transition_post_status ( string $ new_status , string $ old_status , \WP_Post $ post ): void {
131+
132+ if ( $ new_status !== 'publish ' && $ old_status !== 'publish ' ) {
133+ return ;
134+ }
135+
136+ $ supported_post_types = (array ) \get_option ( 'activitypub_support_post_types ' , [] );
137+
138+ if ( ! \in_array ( $ post ->post_type , $ supported_post_types , true ) ) {
139+ return ;
140+ }
141+
142+ if ( ! \class_exists ( 'WP_Rest_Cache_Plugin\Includes\Caching\Caching ' ) ) {
143+ return ;
144+ }
145+
146+ Caching::get_instance ()->delete_object_type_caches ( 'ActivityPub ' );
147+ }
148+ add_action ( 'transition_post_status ' , 'unmus_cache_reset_by_transition_post_status ' , 10 , 3 );
149+
150+ /**
151+ * Set whether the cache represents a single item.
152+ *
153+ * Always return false for ActivityPub endpoints,
154+ * since cache entries cannot be flushed otherwise.
155+ *
156+ * @param bool $is_single Whether the current cache represents a single item
157+ * @param mixed $data Data to cache
158+ * @param string $uri Request URI
159+ * @return bool Whether the cache represents a single item
160+ */
161+
162+ function set_is_single_item ( bool $ is_single , mixed $ data , string $ uri ): bool {
163+ if ( unmus_is_activitypub_endpoint ( $ uri ) ) {
164+ return false ;
165+ }
166+
167+ return $ is_single ;
168+ }
169+ add_filter ( 'wp_rest_cache/is_single_item ' , 'set_is_single_item ' , 10 , 3 );
170+
171+ ?>
0 commit comments