PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 5.13.0
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v5.13.0
5.13.0 5.12.1 5.12.0 5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / classes / WpMatomo / Capabilities.php
matomo / classes / WpMatomo Last commit date
Admin 4 days ago Commands 4 days ago Db 4 days ago Ecommerce 1 month ago Report 1 month ago Site 4 days ago TrackingCode 4 days ago Updater 4 years ago User 4 days ago Workarounds 2 years ago WpStatistics 1 month ago views 1 month ago AIBotTracking.php 1 month ago API.php 1 month ago Access.php 4 days ago AjaxTracker.php 6 months ago Annotations.php 1 month ago Bootstrap.php 1 year ago Capabilities.php 4 days ago Compatibility.php 1 month ago Email.php 1 month ago ErrorNotice.php 1 month ago Feature.php 4 months ago Installer.php 1 month ago Logger.php 1 year ago MinimumRequirements.php 4 days ago MinimumRequirementsNotice.php 4 days ago MinimumRequirementsUpdateGuard.php 4 days ago OptOut.php 3 months ago Paths.php 1 month ago PluginActionLinks.php 4 months ago PluginAdminOverrides.php 1 month ago PluginInit.php 1 month ago PrivacyBadge.php 4 years ago RedirectOnActivation.php 4 months ago Referral.php 4 months ago Request.php 4 days ago Roles.php 4 months ago ScheduledTasks.php 1 month ago Settings.php 4 days ago Site.php 4 days ago TrackingCode.php 1 month ago Uninstaller.php 4 days ago Updater.php 1 month ago User.php 4 days ago
Capabilities.php
234 lines
1 <?php
2 /**
3 * Matomo - free/libre analytics platform
4 *
5 * @link https://matomo.org
6 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
7 * @package matomo
8 */
9
10 namespace WpMatomo;
11
12 use WP_Roles;
13 use WpMatomo\Admin\Menu;
14
15 if ( ! defined( 'ABSPATH' ) ) {
16 exit; // if accessed directly
17 }
18
19 class Capabilities extends Feature {
20
21 const KEY_NONE = 'none_matomo';
22
23 /**
24 * @api
25 */
26 const KEY_VIEW = 'view_matomo';
27
28 /**
29 * @api
30 */
31 const KEY_WRITE = 'write_matomo';
32
33 /**
34 * @api
35 */
36 const KEY_ADMIN = 'admin_matomo';
37
38 /**
39 * @api
40 */
41 const KEY_SUPERUSER = 'superuser_matomo';
42 const KEY_STEALTH = 'stealth_matomo';
43
44 /**
45 * Matomo has Role classes for view/write/admin, but superuser access is a flag on the user
46 * rather than a role, so there is no Matomo constant to reuse for it.
47 */
48 const ROLE_SUPERUSER = 'superuser';
49
50 /**
51 * @var Settings
52 */
53 private $settings;
54
55 public function __construct( $settings ) {
56 $this->settings = $settings;
57 }
58
59 public function register_hooks() {
60 add_action( 'wp_roles_init', [ $this, 'add_capabilities_to_roles' ] );
61 add_filter( 'user_has_cap', [ $this, 'add_capabilities_to_user' ], 10, 4 );
62 add_filter( 'map_meta_cap', [ $this, 'map_meta_cap' ], 10, 4 );
63 }
64
65 /**
66 * Tests only
67 *
68 * @internal
69 */
70 public function remove_hooks() {
71 remove_action( 'wp_roles_init', [ $this, 'add_capabilities_to_roles' ] );
72 remove_filter( 'user_has_cap', [ $this, 'add_capabilities_to_user' ], 10 );
73 remove_filter( 'map_meta_cap', [ $this, 'map_meta_cap' ], 10 );
74 }
75
76 public function map_meta_cap( $caps, $cap, $user_id, $args ) {
77 if ( self::KEY_STEALTH === $cap ) {
78 // in multisite prevent super admin from having their tracking being filtered
79 // a super admin is usually allowed all actions... unless we add do_not_allow
80 if ( is_multisite() && is_super_admin( $user_id ) ) {
81 $stealth = $this->settings->get_global_option( Settings::OPTION_KEY_STEALTH );
82 if ( ! empty( $stealth['administrator'] ) ) {
83 $caps[] = 'do_not_allow';
84 }
85 }
86 }
87
88 if ( Menu::CAP_NOT_EXISTS === $cap
89 && is_multisite()
90 && is_super_admin( $user_id ) ) {
91 $caps[] = 'do_not_allow'; // prevent matomo-analytics submenu to be shown
92 }
93
94 return $caps;
95 }
96
97 public function add_capabilities_to_user( $allcaps, $caps, $args, $user ) {
98 if ( isset( $caps[0] ) ) {
99 $cap_request = $caps[0];
100 switch ( $cap_request ) {
101 // ensure the Matomo capability inheritcance always works
102 case self::KEY_SUPERUSER:
103 if ( $this->has_super_user_capability( $allcaps, $user ) ) {
104 $allcaps[ $cap_request ] = true;
105 }
106 break;
107
108 case self::KEY_VIEW:
109 case self::KEY_WRITE:
110 case self::KEY_ADMIN:
111 if ( empty( $allcaps[ $cap_request ] ) ) {
112 // when user has the above permission we also make sure to add all capabilites below... eg
113 // when user has write... then we ensure the user also has the view capability
114 if ( $this->has_any_higher_permission( $cap_request, $allcaps )
115 || $this->has_super_user_capability( $allcaps, $user ) ) {
116 $allcaps[ $cap_request ] = true;
117 }
118 }
119
120 break;
121 }
122 }
123
124 return $allcaps;
125 }
126
127 private function has_super_user_capability( $allcaps, $user ) {
128 if ( is_multisite() && $this->settings->is_network_enabled() ) {
129 if ( is_super_admin( $user->ID ) ) {
130 // only network manager can be super user in this case
131 return true;
132 }
133 } elseif ( ! empty( $allcaps['administrator'] ) || ( is_multisite() && is_super_admin( $user->ID ) ) ) {
134 return true;
135 }
136
137 return false;
138 }
139
140 /**
141 * @param WP_Roles $roles
142 */
143 public function add_capabilities_to_roles( $roles ) {
144 $access = $this->settings->get_global_option( Settings::OPTION_KEY_CAPS_ACCESS );
145 $stealth = $this->settings->get_global_option( Settings::OPTION_KEY_STEALTH );
146
147 if ( ! empty( $access ) && is_array( $access ) ) {
148 foreach ( $access as $role_name => $cap ) {
149 $role = $roles->get_role( $role_name );
150 if ( $role ) {
151 $role->capabilities[ $cap ] = true;
152 }
153 }
154 }
155
156 if ( ! empty( $stealth ) && is_array( $stealth ) ) {
157 foreach ( $stealth as $role_name => $enabled ) {
158 $role = $roles->get_role( $role_name );
159 if ( $role && $enabled ) {
160 $role->capabilities[ self::KEY_STEALTH ] = true;
161 }
162 }
163 }
164 }
165
166 public function get_all_capabilities_sorted_by_highest_permission() {
167 return array_keys( self::get_capability_role_map() );
168 }
169
170 /**
171 * The Matomo access each Matomo capability corresponds to, highest permission first.
172 *
173 * The values are Matomo role IDs (Piwik\Access\Role\Admin::ID and friends), spelled out
174 * literally because this map is reached from the user_has_cap filter, long before Matomo is
175 * bootstrapped and those classes can be loaded. WpMatomoCapabilitiesTest asserts they match.
176 *
177 * @return array<string, string>
178 */
179 private static function get_capability_role_map() {
180 return [
181 self::KEY_SUPERUSER => self::ROLE_SUPERUSER,
182 self::KEY_ADMIN => 'admin',
183 self::KEY_WRITE => 'write',
184 self::KEY_VIEW => 'view',
185 ];
186 }
187
188 /**
189 * @param int|\WP_User $user
190 * @return string|null a Matomo role ID or self::ROLE_SUPERUSER, null when they are entitled to
191 * no access at all
192 */
193 public static function get_highest_role_for_user( $user ) {
194 foreach ( self::get_capability_role_map() as $capability => $role ) {
195 if ( user_can( $user, $capability ) ) {
196 return $role;
197 }
198 }
199
200 return null;
201 }
202
203 /**
204 * @param string|null $role
205 * @return int
206 */
207 public static function get_role_ranking( $role ) {
208 $roles = array_reverse( array_values( self::get_capability_role_map() ) );
209
210 $rank = array_search( $role, $roles, true );
211
212 return false === $rank ? 0 : $rank + 1;
213 }
214
215 protected function has_any_higher_permission( $cap_to_find, $allcaps ) {
216 $all_caps = $this->get_all_capabilities_sorted_by_highest_permission();
217 if ( ! in_array( $cap_to_find, $all_caps, true ) ) {
218 return false;
219 }
220
221 foreach ( $all_caps as $cap ) {
222 if ( array_key_exists( $cap, $allcaps ) && ! empty( $allcaps[ $cap ] ) ) {
223 // eg if user has super user... then we return right away...
224 return true;
225 }
226 if ( $cap === $cap_to_find ) {
227 return false;
228 }
229 }
230
231 return false;
232 }
233 }
234