Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
89.19% covered (success)
89.19%
66 / 74
0.00% covered (danger)
0.00%
0 / 2
CRAP
n/a
0 / 0
check_user_mail
62.50% covered (warning)
62.50%
10 / 16
0.00% covered (danger)
0.00%
0 / 1
11.38
inform_to_user
96.77% covered (success)
96.77%
30 / 31
0.00% covered (danger)
0.00%
0 / 1
3
1<?php
2
3/**
4 * @file
5 * Login action: request password recovery (sends recovery email).
6 * Logic inlined from legacy/login/recover.php; no longer requires that file.
7 */
8
9declare(strict_types=1);
10
11require_once __DIR__.'/../../Legacy/mailing/mailing.php';
12
13/** Path to legacy login html templates (recover, etc.). */
14define('RECOVER_HTML_DIR', __DIR__.'/../legacy/login/html/recover');
15
16/**
17 * Checks that the email exists as USER or STAFF; normalizes $usermail to user email.
18 *
19 * Uses central DB (USER, STAFF tables); connection resolved inside.
20 *
21 * @param \ConxHelper $conx Connection helper.
22 * @param string $usermail Email to check (by reference: may be set to user email if staff).
23 * @param \Psr\Log\LoggerInterface $logger Logger for errors.
24 * @return bool True if a valid user/staff was found.
25 */
26function check_user_mail(\ConxHelper $conx, string &$usermail, \Psr\Log\LoggerInterface $logger): bool {
27    if ($conx->global === null) {
28        addlog(__FILE__, LogLevel::Error, "Connection to central database failed.");
29        return false;
30    }
31    $results = [];
32    $res = $conx->global->query('USER', ['email' => $usermail, 'status' => ['PA', 'AC']], $results);
33    if ($res && count($results) > 0) {
34        return true;
35    }
36
37    $results = [];
38    $res = $conx->global->query('STAFF', ['email' => $usermail, 'status' => 'AC'], $results);
39    if ($res && count($results) > 0) {
40        $res = $conx->global->query('USER', ['objid' => $results[0]['user'], 'status' => ['PA', 'AC']], $results);
41        if ($res && count($results) > 0) {
42            $usermail = $results[0]['email'];
43            return true;
44        }
45    }
46
47    $logger->error("No valid users/waiters found for email '".$usermail."'.");
48    return false;
49}
50
51/**
52 * Sends recovery email and stores authorization key.
53 *
54 * Uses central DB for add_authorization; connection resolved inside.
55 *
56 * @param \ConxHelper $conx Connection helper.
57 * @param string $lang Language code.
58 * @param string $usermail Recipient email.
59 * @return bool True if email sent and authorization stored.
60 */
61function inform_to_user(\ConxHelper $conx, string $lang, string $usermail): bool {
62    $language = new Language($lang);
63
64    $html = '';
65    email_begin($html, '@password_recovery_title');
66    $content1 = file_get_contents(RECOVER_HTML_DIR.'/1.html');
67    $content2 = file_get_contents(RECOVER_HTML_DIR.'/2.html');
68    $content3 = file_get_contents(RECOVER_HTML_DIR.'/3.html');
69    email_content($html, $content1, $content2, $content3);
70    email_end($html, '@password_recovery_footer');
71
72    $replace = [];
73    $search = [
74        '@password_recovery_title',
75        '@password_recovery_footer',
76        '@recover_email_reason',
77        '@recover_email_norespond',
78        '@recover_email_ignore',
79        '@recover_email_accessdata',
80        '@recover_email_follow_link',
81        '@recover_email_onlogin',
82        '@recover_email_regenerate'
83    ];
84    foreach ($search as $str) {
85        $replace[] = $language->translate($str);
86    }
87
88    srand();
89    $recover_authorization_key = sprintf('%04x%04x%04x%04x', rand(0, 0xFFFF), rand(0, 0xFFFF), rand(0, 0xFFFF), rand(0, 0xFFFF));
90    $search[] = '@REGENERATE_ONCLICK_URL';
91    $replace[] = AppConstants::AppUrl().'login/regenerate?lang='.$lang.'&authorization='.$recover_authorization_key;
92
93    $subject = $language->translate('@password_recovery_title');
94    $html = str_replace($search, $replace, $html);
95    if (email_send($html, AppConstants::NoReplyMail, $usermail, $subject)) {
96        return add_authorization($conx, $recover_authorization_key, $usermail);
97    }
98
99    return false;
100}
101
102/**
103 * Action callable: request password recovery (GET device, username, lang).
104 *
105 * Checks user/staff email exists, sends recovery email.
106 *
107 * @param string $body Request body (unused).
108 * @param array<string, mixed> $query Query params: device, username, lang.
109 * @param \ConxHelper $conx Connection helper (from LoginService; uses ->global for central DB).
110 * @param \Psr\Log\LoggerInterface $logger Logger (from LoggerFactory).
111 * @param \UppServices\SessionService $sessionService Session service (unused in recover).
112 * @return array{output: string, contentType: string} JSON output and content type.
113 */
114return function (string $body, array $query, \ConxHelper $conx, \Psr\Log\LoggerInterface $logger, \UppServices\SessionService $sessionService): array {
115    $retval = ApplicationError::Success;
116
117    $deviceid = $query['device'] ?? null;
118    if (!$deviceid) {
119        $logger->error("Missing 'device' parameter in url request");
120        $retval = ApplicationError::Parameters;
121    }
122
123    $username = $query['username'] ?? null;
124    if (success($retval) && !$username) {
125        $logger->error("Mandatory argument 'username' not provided in url parameters.");
126        $retval = ApplicationError::Parameters;
127    }
128
129    $emailForRecovery = null;
130    if (success($retval) && $username !== null && $username !== '') {
131        $emailForRecovery = (string) $username;
132        if (!check_user_mail($conx, $emailForRecovery, $logger)) {
133            $retval = ApplicationError::NotFound;
134        }
135    }
136
137    if (success($retval) && $emailForRecovery !== null) {
138        $lang = (string) ($query['lang'] ?? 'EN');
139        if (!inform_to_user($conx, $lang, $emailForRecovery)) {
140            $logger->warning("Could not set password recovery for '".$emailForRecovery."' email ");
141        }
142    }
143
144    if (success($retval) && $emailForRecovery !== null) {
145        $logger->info("Password recovery request processed for user email address: '".$emailForRecovery."'.");
146    }
147
148    $result = ['errorcode' => $retval];
149    $output = json_encode($result);
150    return ['output' => $output, 'contentType' => 'application/json; charset=utf-8'];
151};