PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.1.0
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.1.0
11.1.1 11.1.0 11.0.5 11.0.4 11.0.3 11.0.2 11.0.1 11.0.0 10.11.1 10.11.0 10.10.2 10.10.1 10.10.0 10.9.1 trunk 10.0.0 10.0.1 10.1.0 10.1.1 10.1.2 10.1.3 10.1.4 10.2.0 10.2.1 10.2.2 All 62 releases
← All changes | back/Controllers/ToggleController.php +92 -17 10.2.2 → 11.1.0 View file →
@@ -1,8 +1,10 @@
1 1 <?php
2 2
3 3 namespace AcyMailing\Controllers;
4 4
5 +use AcyMailing\Classes\ListClass;
6 +use AcyMailing\Classes\MailClass;
5 7 use AcyMailing\Classes\UserClass;
6 8 use AcyMailing\Core\AcymController;
7 9
8 10 class ToggleController extends AcymController
@@ -19,13 +21,15 @@
19 21 $this->defaulttask = 'toggle';
20 22
21 23 $this->defineToggles();
22 24
25 + // Avoid caching issue in Internet Explorer
23 26 acym_noCache();
24 27 }
25 28
26 29 protected function defineToggles(): void
27 30 {
31 + // $this->toggleableColumns[TABLE NAME WITHOUT PREFIX] = array(COLUMN NAME => PRIMARY KEY);
28 32 $this->toggleableColumns['automation'] = ['active' => 'id'];
29 33 $this->toggleableColumns['field'] = [
30 34 'active' => 'id',
31 35 'required' => 'id',
@@ -44,8 +48,9 @@
44 48 $this->toggleableColumns['mail_override'] = ['active' => 'id'];
45 49 $this->toggleableColumns['mailbox_action'] = ['active' => 'id'];
46 50 $this->toggleableColumns['scenario'] = ['active' => 'id'];
47 51
52 + // $this->icons[TABLE NAME WITHOUT PREFIX][COLUMN NAME][VALUE] = ICON CLASS;
48 53 $this->icons['automation']['active'][1] = 'acymicon-check-circle acym__color__green';
49 54 $this->icons['automation']['active'][0] = 'acymicon-times-circle acym__color__red';
50 55 $this->icons['field']['active'][1] = 'acymicon-check-circle acym__color__green';
51 56 $this->icons['field']['active'][0] = 'acymicon-times-circle acym__color__red';
@@ -96,8 +101,9 @@
96 101 $this->tooltips['campaign']['visible'][1] = 'ACYM_VISIBLE';
97 102 $this->tooltips['mail_override']['active'][0] = 'ACYM_INACTIVE';
98 103 $this->tooltips['mail_override']['active'][1] = 'ACYM_ACTIVE';
99 104
105 + // $this->deletableRows[] = TABLE NAME WITHOUT PREFIX;
100 106 $this->deletableRows[] = 'mail';
101 107 $this->deletableRows[] = 'queue';
102 108 }
103 109
@@ -102,9 +108,9 @@
102 108 }
103 109
104 110 public function toggle(): void
105 111 {
106 - acym_checkToken();
112 + wp_verify_nonce(acym_getVar('cmd', '_wpnonce'), 'acymnonce') || die('Invalid Token');
107 113
108 114 $table = acym_getVar('word', 'table', '');
109 115 $field = acym_getVar('cmd', 'field', '');
110 116 $id = acym_getVar('int', 'id', 0);
@@ -116,8 +122,11 @@
116 122 if (empty($table) || empty($field) || empty($id) || empty($this->toggleableColumns[$table][$field])) {
117 123 exit;
118 124 }
119 125
126 + // Security (ACL): per-table check — the 'toggle' exception opens this controller to ~10 roles regardless of table.
127 + $this->checkToggleAcl($table);
128 +
120 129 $preciseMethod = $table.ucfirst($field);
121 130 $globalMethod = $table.'Global';
122 131 if (method_exists($this, $preciseMethod)) {
123 132 $this->$preciseMethod($id, $table, $field, $newValue);
@@ -128,8 +137,9 @@
128 137 }
129 138
130 139 acym_trigger('onAcymToggle'.ucfirst($table).ucfirst($field), [&$id, &$newValue]);
131 140
141 + // Return the replacement icon
132 142 if (empty($this->icons[$table][$field][$newValue])) {
133 143 acym_sendAjaxResponse(acym_translation('ACYM_UNAUTHORIZED_ACCESS'), [], false);
134 144 }
135 145
@@ -143,8 +153,41 @@
143 153
144 154 acym_sendAjaxResponse('', $data);
145 155 }
146 156
157 + // Each toggle icon is only rendered on the page whose ACL the user already holds, so this per-table check blocks only forged cross-feature requests (the 'toggle' exception opens the controller to ~10 roles); overridden as a no-op by FronttoggleController.
158 + protected function checkToggleAcl(string $table): void
159 + {
160 + $tableAcl = [
161 + 'user' => 'users',
162 + 'list' => 'lists',
163 + 'campaign' => 'campaigns',
164 + 'followup' => 'campaigns',
165 + 'automation' => 'automation',
166 + 'segment' => 'segments',
167 + 'scenario' => 'scenarios',
168 + 'form' => 'forms',
169 + 'field' => 'fields',
170 + 'mailbox_action' => 'bounces',
171 + 'rule' => 'bounces',
172 + 'mail_override' => 'override',
173 + ];
174 +
175 + if (empty($tableAcl[$table]) || !acym_isAllowed($tableAcl[$table])) {
176 + acym_sendAjaxResponse(acym_translation('ACYM_ACCESS_DENIED'), [], false);
177 + }
178 + }
179 +
180 + protected function userActive(int $id, string $table, string $field, int $newValue): void
181 + {
182 + $userClass = new UserClass();
183 + if ($newValue === 0) {
184 + $userClass->deactivate([$id]);
185 + } else {
186 + $userClass->reactivate([$id]);
187 + }
188 + }
189 +
147 190 protected function doToggle(int $id, string $table, string $field, int $newValue): void
148 191 {
149 192 $updateQuery = 'UPDATE '.acym_secureDBColumn(ACYM_DBPREFIX.$table);
150 193 $updateQuery .= ' SET `'.acym_secureDBColumn($field).'` = '.$newValue;
@@ -155,21 +198,33 @@
155 198
156 199 public function delete(): void
157 200 {
158 201 if (!acym_isAdmin()) exit;
159 - acym_checkToken();
202 + wp_verify_nonce(acym_getVar('cmd', '_wpnonce'), 'acymnonce') || die('Invalid Token');
160 203
161 204 $table = acym_getVar('word', 'table', '');
162 - $id = acym_getVar('cmd', 'id', 0);
163 - $method = acym_getVar('word', 'method', 'delete');
205 + $id = acym_getVar('int', 'id', 0);
164 206
165 207 if (empty($table) || !in_array($table, $this->deletableRows) || empty($id)) {
166 208 exit;
167 209 }
168 210
211 + if ($table === 'queue') {
212 + $allowed = acym_isAllowed('queue');
213 + } else {
214 + $mailClass = new MailClass();
215 + $allowed = $mailClass->hasUserAccess($id, true);
216 + }
217 +
218 + if (!$allowed) {
219 + acym_sendAjaxResponse(acym_translation('ACYM_ACCESS_DENIED'), [], false);
220 + }
221 +
222 + $method = $table === 'queue' ? 'deleteQueuedByUserIds' : 'delete';
223 +
169 224 $namespaceClass = 'AcyMailing\\Classes\\'.ucfirst($table).'Class';
170 - $elementClass = new $namespaceClass;
171 - $elementClass->$method($id);
225 + $elementClass = new $namespaceClass();
226 + $elementClass->$method([$id]);
172 227
173 228 exit;
174 229 }
175 230
@@ -180,14 +235,14 @@
180 235 if (empty($newValue)) {
181 236 acym_sendAjaxResponse(acym_translation('ACYM_ERROR_SAVING'), [], false);
182 237 }
183 238
184 - $newConfig = new \stdClass();
185 - $newConfig->remindme = json_decode($this->config->get('remindme', '[]'));
186 - if (!in_array($newValue, $newConfig->remindme)) array_push($newConfig->remindme, $newValue);
187 - $newConfig->remindme = json_encode($newConfig->remindme);
239 + $remindMe = json_decode($this->config->get('remindme', '[]'));
240 + if (!in_array($newValue, $remindMe)) {
241 + $remindMe[] = $newValue;
242 + }
188 243
189 - if ($this->config->save($newConfig)) {
244 + if ($this->config->saveConfig(['remindme' => json_encode($remindMe)])) {
190 245 acym_sendAjaxResponse(acym_translation('ACYM_THANKS'));
191 246 } else {
192 247 acym_sendAjaxResponse(acym_translation('ACYM_ERROR_SAVING'), [], false);
193 248 }
@@ -194,14 +249,24 @@
194 249 }
195 250
196 251 public function subscribeOnClick(): void
197 252 {
198 - $userId = acym_getVar('int', 'userid');
199 - $listId = acym_getVar('int', 'listid');
253 + wp_verify_nonce(acym_getVar('cmd', '_wpnonce'), 'acymnonce') || die('Invalid Token');
254 + // Security (ACL): subscription management is restricted to the 'users' role (backend); no-op on front (ownership).
255 + $this->checkToggleAcl('user');
200 256
257 + $userIds = acym_getVar('array', 'userid', []);
258 + $listIds = acym_getVar('array', 'listid', []);
259 +
201 260 $userClass = new UserClass();
202 - $result = $userClass->subscribe($userId, [$listId]);
261 + $userClass->onlyManageableUsers($userIds);
203 262
263 + $listClass = new ListClass();
264 + $listClass->onlyManageableLists($listIds);
265 +
266 + $userClass = new UserClass();
267 + $result = $userClass->subscribe($userIds, $listIds);
268 +
204 269 if ($result) {
205 270 acym_sendAjaxResponse();
206 271 } else {
207 272 acym_sendAjaxResponse('', [], false);
@@ -209,13 +274,23 @@
209 274 }
210 275
211 276 public function unsubscribeOnClick(): void
212 277 {
213 - $userId = acym_getVar('int', 'userid');
214 - $listId = acym_getVar('int', 'listid');
278 + wp_verify_nonce(acym_getVar('cmd', '_wpnonce'), 'acymnonce') || die('Invalid Token');
279 + // Security (ACL): subscription management is restricted to the 'users' role (backend); no-op on front (ownership).
280 + $this->checkToggleAcl('user');
215 281
282 + $userIds = acym_getVar('array', 'userid', []);
283 + $listIds = acym_getVar('array', 'listid', []);
284 +
216 285 $userClass = new UserClass();
217 - $result = $userClass->unsubscribe($userId, [$listId]);
286 + $userClass->onlyManageableUsers($userIds);
287 +
288 + $listClass = new ListClass();
289 + $listClass->onlyManageableLists($listIds);
290 +
291 + $userClass = new UserClass();
292 + $result = $userClass->unsubscribe($userIds, $listIds);
218 293
219 294 if ($result) {
220 295 acym_sendAjaxResponse();
221 296 } else {