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