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