xref: /plugin/passwd/action.php (revision eb872c2a652d2b4294f9c5ebca2ba18675c61627)
1*eb872c2aStomLin1998567<?php
2*eb872c2aStomLin1998567if (!defined('DOKU_INC')) die();
3*eb872c2aStomLin1998567
4*eb872c2aStomLin1998567/**
5*eb872c2aStomLin1998567 * PASSWD Plugin: Handles AJAX captcha refresh and password verification.
6*eb872c2aStomLin1998567 *
7*eb872c2aStomLin1998567 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
8*eb872c2aStomLin1998567 * @author tomLin1998567
9*eb872c2aStomLin1998567 */
10*eb872c2aStomLin1998567class action_plugin_passwd extends DokuWiki_Action_Plugin
11*eb872c2aStomLin1998567{
12*eb872c2aStomLin1998567    public function register(Doku_Event_Handler $controller)
13*eb872c2aStomLin1998567    {
14*eb872c2aStomLin1998567        $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handleAjax');
15*eb872c2aStomLin1998567    }
16*eb872c2aStomLin1998567
17*eb872c2aStomLin1998567    public function handleAjax(&$event, $param)
18*eb872c2aStomLin1998567    {
19*eb872c2aStomLin1998567        if ($event->data == 'passwd_refresh_captcha') {
20*eb872c2aStomLin1998567            $event->preventDefault();
21*eb872c2aStomLin1998567            $this->sendCaptcha();
22*eb872c2aStomLin1998567            return;
23*eb872c2aStomLin1998567        }
24*eb872c2aStomLin1998567
25*eb872c2aStomLin1998567        if ($event->data != 'passwd_check') return;
26*eb872c2aStomLin1998567        $event->preventDefault();
27*eb872c2aStomLin1998567
28*eb872c2aStomLin1998567        global $INPUT, $ID;
29*eb872c2aStomLin1998567        $block  = (int) $INPUT->str('block');
30*eb872c2aStomLin1998567        $passwd = $INPUT->str('passwd');
31*eb872c2aStomLin1998567        $id     = $INPUT->str('id', $ID);
32*eb872c2aStomLin1998567
33*eb872c2aStomLin1998567        $captcha = $this->loadHelper('captcha', false);
34*eb872c2aStomLin1998567        if ($this->isCaptchaRequired($captcha) && !$this->verifyCaptcha($captcha)) {
35*eb872c2aStomLin1998567            return;
36*eb872c2aStomLin1998567        }
37*eb872c2aStomLin1998567
38*eb872c2aStomLin1998567        $blockText = $this->findPasswdBlock($id, $block);
39*eb872c2aStomLin1998567        if ($blockText === false) return;
40*eb872c2aStomLin1998567
41*eb872c2aStomLin1998567        $expected = $this->extractPassword($blockText);
42*eb872c2aStomLin1998567        if ($expected === false) return;
43*eb872c2aStomLin1998567
44*eb872c2aStomLin1998567        if ($passwd !== $expected) {
45*eb872c2aStomLin1998567            $newCaptcha = $this->isCaptchaRequired($captcha) ? $captcha->getHTML() : '';
46*eb872c2aStomLin1998567            echo 'WRONG_PASSWORD|' . $newCaptcha;
47*eb872c2aStomLin1998567            return;
48*eb872c2aStomLin1998567        }
49*eb872c2aStomLin1998567
50*eb872c2aStomLin1998567        $this->renderContent($blockText);
51*eb872c2aStomLin1998567    }
52*eb872c2aStomLin1998567
53*eb872c2aStomLin1998567    /**
54*eb872c2aStomLin1998567     * Check whether captcha verification is enabled and available.
55*eb872c2aStomLin1998567     */
56*eb872c2aStomLin1998567    protected function isCaptchaRequired($captcha)
57*eb872c2aStomLin1998567    {
58*eb872c2aStomLin1998567        return $this->getConf('require_captcha') && $captcha && $captcha->isEnabled();
59*eb872c2aStomLin1998567    }
60*eb872c2aStomLin1998567
61*eb872c2aStomLin1998567    /**
62*eb872c2aStomLin1998567     * Verify the captcha. On failure output error with a fresh captcha.
63*eb872c2aStomLin1998567     *
64*eb872c2aStomLin1998567     * @return bool true if captcha passes (or not required)
65*eb872c2aStomLin1998567     */
66*eb872c2aStomLin1998567    protected function verifyCaptcha($captcha)
67*eb872c2aStomLin1998567    {
68*eb872c2aStomLin1998567        if (!$captcha->check()) {
69*eb872c2aStomLin1998567            echo 'CAPTCHA_FAILED|' . $captcha->getHTML();
70*eb872c2aStomLin1998567            return false;
71*eb872c2aStomLin1998567        }
72*eb872c2aStomLin1998567        return true;
73*eb872c2aStomLin1998567    }
74*eb872c2aStomLin1998567
75*eb872c2aStomLin1998567    /**
76*eb872c2aStomLin1998567     * Read a wiki page and locate the Nth PASSWD block.
77*eb872c2aStomLin1998567     *
78*eb872c2aStomLin1998567     * @param string $id    Page ID
79*eb872c2aStomLin1998567     * @param int    $block Zero-based block index
80*eb872c2aStomLin1998567     * @return string|false The raw block text, or false on failure
81*eb872c2aStomLin1998567     */
82*eb872c2aStomLin1998567    protected function findPasswdBlock($id, $block)
83*eb872c2aStomLin1998567    {
84*eb872c2aStomLin1998567        preg_match_all(
85*eb872c2aStomLin1998567            '/<passwd\b[^>]*?>[\s\S]*?<\/passwd>/',
86*eb872c2aStomLin1998567            rawWiki($id), $matches, PREG_SET_ORDER
87*eb872c2aStomLin1998567        );
88*eb872c2aStomLin1998567
89*eb872c2aStomLin1998567        if (!isset($matches[$block])) {
90*eb872c2aStomLin1998567            echo 'BLOCK_NOT_FOUND';
91*eb872c2aStomLin1998567            return false;
92*eb872c2aStomLin1998567        }
93*eb872c2aStomLin1998567        return $matches[$block][0];
94*eb872c2aStomLin1998567    }
95*eb872c2aStomLin1998567
96*eb872c2aStomLin1998567    /**
97*eb872c2aStomLin1998567     * Extract the password attribute from a PASSWD block.
98*eb872c2aStomLin1998567     *
99*eb872c2aStomLin1998567     * @param string $blockText Raw block text
100*eb872c2aStomLin1998567     * @return string|false The password, or false if missing
101*eb872c2aStomLin1998567     */
102*eb872c2aStomLin1998567    protected function extractPassword($blockText)
103*eb872c2aStomLin1998567    {
104*eb872c2aStomLin1998567        if (!preg_match('/password="([^"]+)"/i', $blockText, $p)) {
105*eb872c2aStomLin1998567            echo 'PASSWORD_NOT_FOUND';
106*eb872c2aStomLin1998567            return false;
107*eb872c2aStomLin1998567        }
108*eb872c2aStomLin1998567        return $p[1];
109*eb872c2aStomLin1998567    }
110*eb872c2aStomLin1998567
111*eb872c2aStomLin1998567    /**
112*eb872c2aStomLin1998567     * Parse and render the inner wikitext of a PASSWD block as XHTML.
113*eb872c2aStomLin1998567     */
114*eb872c2aStomLin1998567    protected function renderContent($blockText)
115*eb872c2aStomLin1998567    {
116*eb872c2aStomLin1998567        preg_match('/^<passwd\b[^>]*?>([\s\S]*?)<\/passwd>$/s', $blockText, $m);
117*eb872c2aStomLin1998567        $instructions = p_get_instructions($m[1]);
118*eb872c2aStomLin1998567        echo p_render('xhtml', $instructions, $info);
119*eb872c2aStomLin1998567    }
120*eb872c2aStomLin1998567
121*eb872c2aStomLin1998567    /**
122*eb872c2aStomLin1998567     * Generate and return a fresh captcha HTML snippet.
123*eb872c2aStomLin1998567     */
124*eb872c2aStomLin1998567    protected function sendCaptcha()
125*eb872c2aStomLin1998567    {
126*eb872c2aStomLin1998567        $captcha = $this->loadHelper('captcha', false);
127*eb872c2aStomLin1998567        if ($captcha && $captcha->isEnabled()) {
128*eb872c2aStomLin1998567            echo $captcha->getHTML();
129*eb872c2aStomLin1998567        }
130*eb872c2aStomLin1998567    }
131*eb872c2aStomLin1998567}
132