xref: /dokuwiki/inc/Action/Resendpwd.php (revision 8c7c53b0321a3cd3116b8d3b2ad27863a38dece7)
1<?php
2
3namespace dokuwiki\Action;
4
5use dokuwiki\Ui\UserResendPwd;
6use dokuwiki\Action\Exception\ActionAbort;
7use dokuwiki\Action\Exception\ActionDisabledException;
8use dokuwiki\Extension\AuthPlugin;
9use dokuwiki\Ui;
10
11/**
12 * Class Resendpwd
13 *
14 * Handle password recovery
15 *
16 * @package dokuwiki\Action
17 */
18class Resendpwd extends AbstractAclAction
19{
20    /** @inheritdoc */
21    public function minimumPermission()
22    {
23        return AUTH_NONE;
24    }
25
26    /** @inheritdoc */
27    public function checkPreconditions()
28    {
29        parent::checkPreconditions();
30
31        /** @var AuthPlugin $auth */
32        global $auth;
33        global $conf;
34        if (isset($conf['resendpasswd']) && !$conf['resendpasswd'])
35            throw new ActionDisabledException(); //legacy option
36        if (!$auth->canDo('modPass')) throw new ActionDisabledException();
37    }
38
39    /** @inheritdoc */
40    public function preProcess()
41    {
42        if ($this->resendpwd()) {
43            throw new ActionAbort('login');
44        }
45    }
46
47    /** @inheritdoc */
48    public function tplContent()
49    {
50        (new UserResendPwd)->show();
51    }
52
53    /**
54     * Send a  new password
55     *
56     * This function handles both phases of the password reset:
57     *
58     *   - handling the first request of password reset
59     *   - validating the password reset auth token
60     *
61     * @author Benoit Chesneau <benoit@bchesneau.info>
62     * @author Chris Smith <chris@jalakai.co.uk>
63     * @author Andreas Gohr <andi@splitbrain.org>
64     * @fixme this should be split up into multiple methods
65     * @return bool true on success, false on any error
66     */
67    protected function resendpwd()
68    {
69        global $lang;
70        global $conf;
71        /* @var AuthPlugin $auth */
72        global $auth;
73        global $INPUT;
74
75        if (!actionOK('resendpwd')) {
76            msg($lang['resendna'], -1);
77            return false;
78        }
79
80        $token = preg_replace('/[^a-f0-9]+/', '', $INPUT->str('pwauth'));
81
82        if ($token) {
83            // we're in token phase - get user info from token
84
85            $tfile = $conf['cachedir'] .'/'. $token[0] .'/'. $token . '.pwauth';
86            if (!file_exists($tfile)) {
87                msg($lang['resendpwdbadauth'], -1);
88                $INPUT->remove('pwauth');
89                return false;
90            }
91            // token is only valid for 3 days
92            if ((time() - filemtime($tfile)) > (3 * 60 * 60 * 24)) {
93                msg($lang['resendpwdbadauth'], -1);
94                $INPUT->remove('pwauth');
95                @unlink($tfile);
96                return false;
97            }
98
99            $user = io_readfile($tfile);
100            $userinfo = $auth->getUserData($user, $requireGroups = false);
101            if (empty($userinfo['mail'])) {
102                msg($lang['resendpwdnouser'], -1);
103                return false;
104            }
105
106            if (!$conf['autopasswd']) { // we let the user choose a password
107                $pass = $INPUT->str('pass');
108
109                // password given correctly?
110                if (!$pass) return false;
111                if ($pass != $INPUT->str('passchk')) {
112                    msg($lang['regbadpass'], -1);
113                    return false;
114                }
115
116                // change it
117                if (!$auth->triggerUserMod('modify', [$user, ['pass' => $pass]])) {
118                    msg($lang['proffail'], -1);
119                    return false;
120                }
121
122            } else { // autogenerate the password and send by mail
123
124                $pass = auth_pwgen($user);
125                if (!$auth->triggerUserMod('modify', [$user, ['pass' => $pass]])) {
126                    msg($lang['proffail'], -1);
127                    return false;
128                }
129
130                if (auth_sendPassword($user, $pass)) {
131                    msg($lang['resendpwdsuccess'], 1);
132                } else {
133                    msg($lang['regmailfail'], -1);
134                }
135            }
136
137            @unlink($tfile);
138            return true;
139
140        } else {
141            // we're in request phase
142
143            if (!$INPUT->post->bool('save')) return false;
144
145            if (!$INPUT->post->str('login')) {
146                msg($lang['resendpwdmissing'], -1);
147                return false;
148            } else {
149                $user = trim($auth->cleanUser($INPUT->post->str('login')));
150            }
151
152            $userinfo = $auth->getUserData($user, $requireGroups = false);
153            if (empty($userinfo['mail'])) {
154                msg($lang['resendpwdnouser'], -1);
155                return false;
156            }
157
158            // generate auth token
159            $token = md5(auth_randombytes(16)); // random secret
160            $tfile = $conf['cachedir'] .'/'. $token[0] .'/'. $token .'.pwauth';
161            $url = wl('', ['do' => 'resendpwd', 'pwauth' => $token], true, '&');
162
163            io_saveFile($tfile, $user);
164
165            $text = rawLocale('pwconfirm');
166            $trep = [
167                'FULLNAME' => $userinfo['name'],
168                'LOGIN' => $user,
169                'CONFIRM' => $url
170            ];
171
172            $mail = new \Mailer();
173            $mail->to($userinfo['name'] .' <'. $userinfo['mail'] .'>');
174            $mail->subject($lang['regpwmail']);
175            $mail->setBody($text, $trep);
176            if ($mail->send()) {
177                msg($lang['resendpwdconfirm'], 1);
178            } else {
179                msg($lang['regmailfail'], -1);
180            }
181            return true;
182        }
183        // never reached
184    }
185}
186