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/Classes/FieldClass.php +38 -12 11.0.5 → 11.1.0 View file →
@@ -142,8 +142,9 @@
142 142 }
143 143
144 144 public function store(int $userID, array $fields, bool $ajax = false): void
145 145 {
146 + $uploadedFileFields = [];
146 147 $customField = acym_getVar('array', 'customField', [], 'FILES');
147 148 if (!empty($customField['tmp_name'])) {
148 149 $uploadFolder = trim(acym_cleanPath(html_entity_decode(acym_getFilesFolder(true))), DS.' ').DS;
149 150 $uploadPath = acym_cleanPath(ACYM_ROOT.$uploadFolder.'userfiles'.DS.$userID.DS);
@@ -160,10 +161,11 @@
160 161 $fileName = $customField['name'][$key];
161 162 while (is_array($fileName) && isset($fileName[0])) {
162 163 $fileName = $fileName[0];
163 164 }
165 + $fileName = basename($fileName);
164 166
165 - if (!preg_match('#\.('.implode('|', $allowedExtensions).')$#Ui', $fileName)) {
167 + if (!acym_fileNameValid($fileName) || !preg_match('#\.('.implode('|', array_map('preg_quote', $allowedExtensions)).')$#i', $fileName)) {
166 168 $ext = substr($fileName, strrpos($fileName, '.') + 1);
167 169 if ($ajax) {
168 170 $this->errors[] = acym_translationSprintf(
169 171 'ACYM_ACCEPTED_TYPE',
@@ -184,9 +186,9 @@
184 186
185 187 continue;
186 188 }
187 189
188 - if (!acym_uploadFile($value, $uploadPath.$fileName)) {
190 + if (!acym_isPathWithinDirectory($uploadPath, $uploadPath.$fileName) || !acym_uploadFile($value, $uploadPath.$fileName)) {
189 191 if ($ajax) {
190 192 $this->errors[] = acym_translation('ACYM_ERROR_SAVING');
191 193 } else {
192 194 acym_enqueueMessage(acym_translation('ACYM_ERROR_SAVING'), 'error');
@@ -193,9 +195,10 @@
193 195 }
194 196
195 197 continue;
196 198 }
197 - $fields[$key] = $customField['name'][$key];
199 + $fields[$key] = $fileName;
200 + $uploadedFileFields[$key] = true;
198 201 }
199 202 }
200 203
201 204 if (empty($fields)) return;
@@ -248,8 +251,13 @@
248 251 if (in_array($field->type, ['text', 'textarea']) && !empty($fieldOptions->max_characters)) {
249 252 $value = substr($value, 0, $fieldOptions->max_characters);
250 253 }
251 254
255 + // A file field value can only be set through an actual upload, never through a plain posted string
256 + if ($field->type === 'file' && strlen($value) !== 0 && empty($uploadedFileFields[$id])) {
257 + continue;
258 + }
259 +
252 260 // If deleting a file field, also delete the physical file
253 261 if ($field->type === 'file' && strlen($value) === 0) {
254 262 $oldValue = acym_loadResult(
255 263 'SELECT `value` FROM #__acym_user_has_field WHERE `user_id` = '.intval($userID).' AND `field_id` = '.intval($id)
@@ -258,15 +266,21 @@
258 266 $fileName = @json_decode($oldValue, true);
259 267 if (is_array($fileName)) $fileName = $fileName[0];
260 268 if (empty($fileName)) $fileName = $oldValue;
261 269
262 - $uploadFolder = trim(acym_cleanPath(html_entity_decode(acym_getFilesFolder(true))), DS.' ').DS;
263 - // Try new path (with user folder) first, then legacy path (without user folder)
264 - $filePath = acym_cleanPath(ACYM_ROOT.$uploadFolder.'userfiles'.DS.$userID.DS.$fileName);
265 - if (!file_exists($filePath)) {
266 - $filePath = acym_cleanPath(ACYM_ROOT.$uploadFolder.'userfiles'.DS.$fileName);
270 + $fileName = basename($fileName);
271 + if (acym_fileNameValid($fileName)) {
272 + $uploadFolder = trim(acym_cleanPath(html_entity_decode(acym_getFilesFolder(true))), DS.' ').DS;
273 + $userfilesBase = acym_cleanPath(ACYM_ROOT.$uploadFolder.'userfiles'.DS);
274 + // Try new path (with user folder) first, then legacy path (without user folder)
275 + $filePath = acym_cleanPath($userfilesBase.$userID.DS.$fileName);
276 + if (!file_exists($filePath)) {
277 + $filePath = acym_cleanPath($userfilesBase.$fileName);
278 + }
279 + if (acym_isPathWithinDirectory($userfilesBase, $filePath)) {
280 + acym_deleteFile($filePath);
281 + }
267 282 }
268 - acym_deleteFile($filePath);
269 283 }
270 284 }
271 285
272 286 // The user removed a value, don't add an empty line and remove any previous value from the bd
@@ -561,8 +575,19 @@
561 575 : json_encode($defaultValue)
562 576 );
563 577 }
564 578
579 + $allowedFieldNameTags = array_merge(SecurityHelper::ALLOWED_HTML_FIELD_NAME, [
580 + 'a' => [
581 + 'href' => true,
582 + 'target' => true,
583 + 'title' => true,
584 + 'class' => true,
585 + 'rel' => true,
586 + 'aria-label' => true,
587 + ],
588 + ]);
589 +
565 590 $labelTypes = ['text', 'textarea', 'single_dropdown', 'multiple_dropdown', 'custom_text', 'language'];
566 591 $titleTypes = ['date', 'radio', 'checkbox', 'file'];
567 592
568 593 $useLabel = $displayOutside && (in_array($field->id, [1, 2]) || in_array($field->type, $labelTypes));
@@ -579,14 +604,14 @@
579 604 $groupLabelId = 'acym__field__label__'.intval($field->id).'_'.acym_rand(1000, 9999);
580 605 echo '<div class="cell margin-top-1" role="group" aria-labelledby="'.esc_attr($groupLabelId).'"'.($field->required ? ' aria-required="true"' : '').'>';
581 606 echo '<div id="'.esc_attr($groupLabelId).'" class="acym__users__creation__fields__title">'.wp_kses(
582 607 $field->name,
583 - SecurityHelper::ALLOWED_HTML_FIELD_NAME
608 + $allowedFieldNameTags
584 609 ).'</div>';
585 610 } else {
586 611 echo '<div class="cell margin-top-1"><div class="acym__users__creation__fields__title">'.wp_kses(
587 612 $field->name,
588 - SecurityHelper::ALLOWED_HTML_FIELD_NAME
613 + $allowedFieldNameTags
589 614 ).'</div>';
590 615 }
591 616 }
592 617
@@ -799,9 +824,10 @@
799 824 } else {
800 825 $downloadUrl = '';
801 826 if (!empty($defaultValue) && !empty($user->id)) {
802 827 $fileName = is_array($defaultValue) ? $defaultValue[0] : $defaultValue;
803 - if (!empty($fileName)) {
828 + $fileName = basename($fileName);
829 + if (!empty($fileName) && acym_fileNameValid($fileName)) {
804 830 $uploadFolder = trim(acym_cleanPath(html_entity_decode(acym_getFilesFolder(true))), DS.' ').DS;
805 831 $userFilePath = $uploadFolder.'userfiles'.DS.$user->id.DS.$fileName;
806 832 $legacyFilePath = $uploadFolder.'userfiles'.DS.$fileName;
807 833