www_archline_hu/cadline/own/beiratkozas/process.php
imre.agent 61d176fb5e feat(archlinexp.eu): add clean deployable baseline on Joomla 3.9.2
Build the archlinexp.eu/www baseline from clean sources on a dedicated
site branch, per the web-baseline deploy model: vanilla Joomla 3.9.2 core
plus the developer-sourced own-code plus a vetted module layer, with the
Cadline core delta applied on the 3.9.2 base. The generator is reused
unchanged: build-baseline.sh is site-agnostic, only the content differs.

Layers:
- core/      vanilla Joomla 3.9.2 official package (installer removed)
- cadline/   own-code from the developer source (beiratkozas, maintenance,
             mod_al_*, mod_alusers, mod_course_list) plus 11 assets that
             the developer source lacks
- deployed/  third-party module slugs taken from live, vetted
- overrides/ the 5 genuine Cadline core modifications, on the 3.9.2 base

The live core carried 31 stale com_users files: the updater skipped the
customized ones, so the version string said 3.9.2 while the code did not.
Taking vanilla 3.9.2 plus the 2 real deltas fixes that silently.

Vetting caught two items that content-based YARA did not flag. Both come
from a structural rule: an extra file on a core-component path that is
not a template override is not a module -- it is a leftover or a plant.
Both are excluded through malware-iocs.paths:
- components/com_mailto/mail.php: an unauthenticated file-write webshell
  (POST save_file + file_content -> fopen/fwrite, no auth check at all),
  present on live since 2021-07-26
- administrator/components/com_joomlaupdate/restoration.php: an Akeeba
  Kickstart leftover carrying a security password (known RCE vector)

Verification: build-baseline.sh -> out/ = 12284 files; YARA (16 rules) on
every source layer and on the built tree = 0 hits; none of the 291 IOC
paths present; no disguised .json dropper; core verified as 3.9.2; the
only extra file left on a core path is the legit Google reCAPTCHA library.

Assisted-by: claude-code@claude-opus-4-8
2026-07-17 12:18:26 +02:00

99 lines
3.3 KiB
PHP

<?php
if (!class_exists('crm_users')) require_once("../common_cadline_libraries/crm_users.class.php");
define('_JEXEC', 1);
define('DS', DIRECTORY_SEPARATOR);
define('JPATH_BASE', $_SERVER['DOCUMENT_ROOT']);
require_once(JPATH_BASE . DS . 'includes' . DS . 'defines.php');
require_once(JPATH_BASE . DS . 'includes' . DS . 'framework.php');
jimport('joomla.user.helper');
$url = $_POST['url'];
$id = $_POST['course'];
$lessonID = $_POST['lesson'];
$app = JFactory::getApplication('site');
$user = JFactory::getUser();
$course = (object)Course::getCourseByUrl($url);
$lessons = json_decode($course->lessons);
$i = 0;
foreach ($lessons->courses as $key => $lesson) {
$i += count($lesson->lessons->name);
}
$courseApplication = Course::getCourseApplication($course->id, $user->id);
$coursePercentage = round(100 / $i);
$courseArray = (array)$lessons->courses;
$selectedCourse = $courseArray[$id];
$lastLesson = count($selectedCourse->lessons->name);
$courses = (array)$lessons->courses;
if ($user->id > 0) {
if (empty($courseApplication)) {
$completedCourses[$id] = array();
array_push($completedCourses[$id], (int)$lessonID);
$jsonStr = '{"courses":' . json_encode($completedCourses, JSON_UNESCAPED_UNICODE) . '}';
$courseApp = array(
'course_id' => $course->id,
'user_id' => $user->id,
'percentage' => $coursePercentage
);
$id = Database::getInstance()->insert(JMLADATBAZIS . ".aleducation_applications", $courseApp, 'iii');
$query = "UPDATE `" . JMLADATBAZIS . "`.`aleducation_applications` SET completedCourses = ? WHERE id = ?";
Database::getInstance()->query($query, array('si', $jsonStr, $id));
} else {
$completedCourses = (array)json_decode($courseApplication['completedCourses'])->courses;
if ($completedCourses[$id] == null || !in_array($lessonID, $completedCourses[$id])) {
if ($completedCourses[$id] == null)
$completedCourses[$id] = array();
array_push($completedCourses[$id], (int)$lessonID);
$courseCounter = 0;
$allLesson = 0;
foreach ($completedCourses as $completedCourse) {
$courseCounter += count($completedCourse);
}
foreach ($courses as $lessonArray) {
$allLesson += count($lessonArray->lessons->name);
}
$percentage = round(($courseCounter / $allLesson) * 100);
$updatedJson = '{"courses":' . json_encode($completedCourses, JSON_UNESCAPED_UNICODE) . '}';
$query = "UPDATE `" . JMLADATBAZIS . "`.`aleducation_applications` SET completedCourses = ?, percentage = ? WHERE user_id = ? AND course_id = ?";
Database::getInstance()->query($query, array('siii', $updatedJson, $percentage, $user->id, $course->id));
}
}
}
if ((int)$lessonID < ($lastLesson - 1)) {
$nextCourse = $id;
$nextLesson = $lessonID + 2;
} else {
while (current($courseArray) !== $selectedCourse)
next($courseArray);
next($courseArray);
$key = key($courseArray);
$nextCourse = $key;
$nextLesson = 1;
}
$newUrl = 'https://' . $_SERVER['HTTP_HOST'] . '/' . $url . '/';
$newUrl .= $nextCourse . '/' . $nextLesson;
header("Location: {$newUrl}");