xref: /dokuwiki/_test/tests/lib/exe/ajax_requests.test.php (revision e8c9256af140fbe66c11ee76e814e1a226fd61af)
1<?php
2
3/**
4 * @group ajax
5 */
6class ajax_requests_test extends DokuWikiTest {
7
8    /**
9     * DataProvider for the builtin Ajax calls
10     *
11     * @return array
12     */
13    public function defaultCalls() {
14        return [
15            // TODO: better logic and DOM walks
16            // Call           | POST     |   regexp pattern to match
17            [ 'linkwiz',      ['q' => ''], '/^<div class="odd type_d/' ],
18            [ 'suggestions',  ['q' => ''], null ],
19            [ 'lock',         ['id' => ''], null ],
20            [ 'draftdel',     ['id' => ''], null ],
21            [ 'medians',      ['ns' => 'some:ns'], null ],
22            [ 'medialist',    ['ns' => '', 'recent' => '', 'do' => ''], null ],
23            [ 'mediadetails', ['image' => ''], null ],
24            [ 'mediadiff',    ['image' => ''], null ],
25            [ 'mediaupload',  ['mediaid' => '', 'qqfile' => '' ], null ], // $_FILES
26            [ 'index',        ['idx' => ''], null ],
27            [ 'linkwiz',      ['q' => ''], null ],
28        ];
29    }
30
31    /**
32     * @dataProvider defaultCalls
33     * @param string $call
34     * @param array $post
35     * @param string $regexp
36     */
37    public function test_defaultCallsExist($call, $post, $regexp) {
38
39        $request = new TestRequest();
40        $response = $request->post(['call'=> $call]+$post, '/lib/exe/ajax.php');
41        $this->assertNotEquals("AJAX call '$call' unknown!\n", $response->getContent());
42
43        if (!empty($regexp)) {
44            $this->assertMatchesRegularExpression($regexp, $response->getContent());
45        }
46    }
47
48    /**
49     * callMediaupload must normalize the namespace with cleanID() before it is used.
50     *
51     * regression test for XSS reflection and passing unclened data to the ACL check
52     */
53    public function test_mediaupload_reflects_cleaned_namespace() {
54        $request = new TestRequest();
55        $response = $request->post(
56            ['call' => 'mediaupload', 'ns' => 'Foo"><script>x</script>'],
57            '/lib/exe/ajax.php'
58        );
59
60        $result = json_decode($response->getContent(), true);
61        $this->assertIsArray($result);
62        $this->assertSame(
63            'foo_script_x_script',
64            $result['ns'],
65            'the raw namespace must be cleaned before it is used'
66        );
67    }
68
69    public function test_CallNotProvided() {
70        $request = new TestRequest();
71        $response = $request->post([], '/lib/exe/ajax.php');
72        $this->assertEquals('', $response->getContent());
73    }
74
75    public function test_UnknownCall() {
76        $call = 'unknownCALL';
77        $request = new TestRequest();
78        $response = $request->post(['call'=> $call], '/lib/exe/ajax.php');
79        $this->assertEquals("AJAX call '$call' unknown!\n", $response->getContent());
80    }
81
82
83    public function test_EventOnUnknownCall() {
84        global $EVENT_HANDLER;
85        $call = 'unknownCALL';
86        $request = new TestRequest();
87
88        // referenced data from event hook
89        $hookTriggered = false;
90        $eventDataTriggered = '';
91        $dataTriggered = '';
92        $postTriggered = '';
93
94        $hookTriggered_AFTER = false;
95        $eventDataTriggered_AFTER  = '';
96        $dataTriggered_AFTER  = '';
97        $postTriggered_AFTER  = '';
98
99        $EVENT_HANDLER->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', null,
100            function($event, $data) use (&$hookTriggered, &$dataTriggered, &$eventDataTriggered, &$postTriggered) {
101                /** @var Doku_Event $event */
102                $hookTriggered = true;
103                $dataTriggered = $data;
104                $eventDataTriggered = $event->data;
105                $postTriggered = $GLOBALS['INPUT']->post->str('q');
106                $event->preventDefault();
107                $event->stopPropagation();
108                echo "captured event BEFORE\n";
109            }, 'some passed data'
110        );
111
112        $EVENT_HANDLER->register_hook('AJAX_CALL_UNKNOWN', 'AFTER', null,
113            function($event, $data) use (&$hookTriggered_AFTER , &$dataTriggered_AFTER , &$eventDataTriggered_AFTER , &$postTriggered_AFTER ) {
114                /** @var Doku_Event $event */
115                $hookTriggered_AFTER  = true;
116                $dataTriggered_AFTER  = $data;
117                $eventDataTriggered_AFTER  = $event->data;
118                $postTriggered_AFTER  = $GLOBALS['INPUT']->post->str('q');
119                $event->preventDefault();
120                $event->stopPropagation();
121                echo "captured event AFTER";
122            }, 'some passed data AFTER'
123        );
124
125
126        $response = $request->post(['call'=> $call, 'q' => 'some-post-param'], '/lib/exe/ajax.php');
127
128        // BEFORE
129        $this->assertEquals(true, $hookTriggered, 'Testing plugin did not trigger!');
130        $this->assertEquals('some passed data', $dataTriggered);
131        $this->assertEquals($call, $eventDataTriggered, 'Must pass call name as event data');
132        $this->assertEquals('some-post-param', $postTriggered);
133
134        // AFTER
135        $this->assertEquals(true, $hookTriggered_AFTER, 'Testing plugin did not trigger!');
136        $this->assertEquals('some passed data AFTER', $dataTriggered_AFTER);
137        $this->assertEquals($call, $eventDataTriggered_AFTER, 'Must pass call name as event data');
138        $this->assertEquals('some-post-param', $postTriggered_AFTER);
139
140        //output
141        $this->assertEquals("captured event BEFORE\ncaptured event AFTER", $response->getContent());
142
143    }
144}
145